Ankündigung

Einklappen
Keine Ankündigung bisher.

OOP / software design verständnis

Einklappen

Neue Werbung 2019

Einklappen
X
  • Filter
  • Zeit
  • Anzeigen
Alles löschen
neue Beiträge

  • OOP / software design verständnis

    hallo,

    welche klassen, welche methoden, welche eigenschaften - was macht sinn? ich möchte das an einem beispiel demonstrieren was ich meine:

    PHP-Code:
    <?php

    class Produkt {
        public 
    $name;
        public 
    $beschreibung;
        public 
    $media;
        public 
    $status;
        
        function 
    getName() {}
        function 
    setName($v) {}
        
        function 
    getBeschreibung() {}
        function 
    setBeschreibung($v) {}
        
        function 
    getMedia() {}
        function 
    setMedia($v) {}
        
        function 
    getStatus() {}
        function 
    setStatus($v) {}
    }

    class 
    Kategorie {
        public 
    $name;
        public 
    $beschreibung;
        public 
    $media;
        public 
    $status;

        function 
    getName() {}
        function 
    setName($v) {}

        function 
    getBeschreibung() {}
        function 
    setBeschreibung($v) {}

        function 
    getMedia() {}
        function 
    setMedia($v) {}

        function 
    getStatus() {}
        function 
    setStatus($v) {}
    }

    // komprimiert
    class Kategorie {
        public 
    $prop = array();
        
        function 
    getProp() {}
        function 
    setProp($v) {}
    }

    ?>
    also wie oben zu sehen habe ich produkte die in kategorien geordnet sind - wenn ich da für produkte und kategorien jeweils eine klasse mache sind das eigentlich die gleichen eigenschaften. für mich stellt sich auch die frage ob man wirklich jede eigenschaft einzeln in der klasse definieren muss oder ob man die ganzen eigenschaften in ein array gibt wo man darauf zugreifen kann $prop['name'], ... - die letzte kategorie klasse könnte ja auch in den prop den wert istProdukt oder istKategorie haben?

    bitte helft mir da das ganze besser zu verstehen welcher ansatz da der richtige ist - klar ich sehe bei der letzten klasse nicht welche eigenschaften die klasse hat - ist das wirklich ein nachteil - kann man ja in der doku festhalten was es für prop gibt? wenn ich die anzahl der codezeilen sehe ist das kein vergleich - in allen beispielen die ich zu OOP so gesehen habe wird jedoch eher gem. den ersten beiden klassen das ganze veranschaulicht das hier wirklich jede eigenschaft abgebildet wird.

    danke für feedback

  • #2
    Hallöchen,

    zunächst solltest du deine Eigenschaften nicht mittels public für alle Welt öffentlich zugänglich machen. Der Weg über Getter / Setter hat einen entscheidenden Vorteil für dich: du kannst auf Anfragen / Änderungen reagieren, Validierungen durchführen oder andere sinnvolle Dinge tun.

    Was dein "komprimiertes" Beispiel angeht, würde ich den Weg über die Interzeptormethoden __get und __set gehen. Das könnte so aussehen:

    PHP-Code:
    <?php

    namespace phpde;

    use 
    RuntimeException;

    class 
    Product{
        
    /**
         * @var array
         */
        
    protected $values = [
            
    'id' => null,
            
    'name' => null,
            
    'description' => null
        
    ];

        
    /**
         * @param  string $property
         * @return boolean
         */
        
    protected function has($property){
            return 
    array_key_exists($property$this->values);
        }

        
    /**
         * @param  string $property
         * @return mixed
         */
        
    public function __get($property){
            if(
    $this->has($property)){
                return 
    $this->values[$property];
            }
            throw new 
    RuntimeException('Property ' . (string)$property ' not found.');
        }

        
    /**
         * @param string $property
         * @param mixed  $value
         */
        
    public function __set($property$value){
            if(
    $this->has($property)){
                
    $this->values[$property] = $value;
            } else{
                throw new 
    RuntimeException('Property ' . (string)$property ' not found.');
            }
        }
    }
    PHP-Code:
    /**
     * Beispiel
     */
    $smartphone = new Product;
    $smartphone->name 'Apple iPhone';
    $smartphone->description 'Awesome. Crazy. Banana.'
    Ich persönlich definiere gerne alle Eigenschaften direkt in der Klasse und schreibe die Getter / Setter selbst oder lasse sie automatisch generieren. Hin und wieder nutze ich aber auch diese Quick & Dirty Variante. Hängt aber ganz vom Projekt.

    Viele Grüße,
    lotti
    [SIZE="1"]Atwood's Law: any application that can be written in JavaScript, will eventually be written in JavaScript.[/SIZE]

    Kommentar


    • #3
      hi,

      danke für das feedback - also macht es schon sinn die eigenschaften in ein array zu packen oder würdet ihr das so nicht empfehlen - vor/nachteil?

      wo ich mir auch immer schwer tue ist die notwendigen klassen zu definieren - also für was braucht es alles eine eigene klasse, was packt man in eine klasse etc. - gibt es da einen tip wie man da am besten die struktur aufbaut?

      geht das wirklich nur über erfahrung oder kann man sich da an einem gewissen leitfaden orientieren das man da nicht unnötig viele klassen generiert aber auch nicht zu viel logik nur in eine klasse packt ...

      danke!

      Kommentar


      • #4
        Zitat von helpmeplease Beitrag anzeigen
        gibt es da einen tip wie man da am besten die struktur aufbaut?
        OOP ist an die reale Welt angelehnt. Sprich: Denk von deinen Klassen, als wären sie Beschreibungen echter Dinge in der Welt.

        Was macht dein Produkt aus? Was identifiziert es und wie kannst du es von anderen unterscheiden? Welche Eigenschaften hat es? Das alles kommt vermutlich in Eigenschaften/Variablen der Klasse.

        Kann ein Produkt etwas tun? Dann beschreibe dies mit Methoden.

        Oder tut jemand etwas mit einem Produkt? Dann hat das Produkt vermutlich selbst garkeine Methoden, sondern es gibt andere Klassen, die Produkte verwenden und etwas mit ihnen tun.

        Wer sind diese anderen "Akteure"? Was tun sie? Wer ist für was verantwortlich? Eine Klasse, die sich damit beschäftigt, Produkt zu suchen hat andere Methoden, als eine Klasse, die Produkte in einen Warenkorb legt und diesen organsiert.

        Diese Herangehensweise stößt schnell an Grenzen, aber für den Anfang kann man schon versuchen, die reale Welt so gut es eben geht abzubilden.

        Natürlich alles unter der Einschränkung der tatsächlichen Anforderungen.

        Wenn ein Produkt eine Eigenschaft "Preis" hat, ist das erstmal nur eine Variable der Klasse. Wenn du aber z.B. je nach Kunde verschiedene Preise hast, musst du vermutlich noch eine "PreisFinder"-Klasse machen, die mit dem Input "Produkt" und "Kunde" den korrekten Preis sucht.

        So musste dich halt durcharbeiten und versuchen, das was du tatsächlich brauchst, in Klassen, Eigenschaften und Methoden zu gießen.
        [URL="http://goo.gl/6Biyf"]Lerne Grundlagen[/URL] | [URL="http://sscce.org/"]Schreibe gute Beispiele[/URL] | [URL="http://goo.gl/f2jR7"]PDO > mysqli > mysql[/URL] | [URL="http://goo.gl/jvfSZ"]Versuch nicht, das Rad neu zu erfinden[/URL] | [URL="http://goo.gl/T2PU5"]Warum $foo[bar] böse ist[/URL] | [URL="http://goo.gl/rrfzO"]SQL Injections[/URL] | [URL="http://goo.gl/Q81WJ"]Hashes sind keine Verschlüsselungen![/URL] | [URL="http://goo.gl/2x0e2"]Dein E-Mail Regex ist falsch[/URL]

        Kommentar


        • #5
          Nachteil: Der allergrößte Teil der IDEs (etwa Auto-Vervollständigung) und Codeanalyse-Tools kann mit der Klasse nicht mehr wahnsinnig viel anfangen. Zudem schaffst du keine verwertbar definierten Schnittstellen für Type-Hinting. (Ein Objekt schafft es mit einer getProp()-Methode durch den Type-Hint, dass es aber die eigentlich benötigten Eigenschaften nicht gesetzt hat, fällt erst später auf.) Und alles ist nur kompliziert dokumentierbar.

          Vorteile: Sehe ich in Relation zu den krassen Nachteile spontan keine. „Tipparbeit“ und dergleichen zählt für mich nicht wirklich.

          Für manche spezialisierte Objekte kann man dieses „Property-Bag“-Format aber trotzdem nutzen. Ich denke etwa an Objekte, die Variablen für Templates halten (da ist die Anzahl der Instanzvariablen dann vermutlich sogar dynamisch) oder an Config-Objekte. Das sind tendenziell eher Objekte, die – jedenfalls in Teilen – mehr so eine Art Liste sind, statt über ihre Eigenschaften einen bestimmten Zustand zu verkörpern, der validierbar wäre.

          Kommentar


          • #6
            Hallöchen,

            Zitat von helpmeplease Beitrag anzeigen
            danke für das feedback - also macht es schon sinn die eigenschaften in ein array zu packen oder würdet ihr das so nicht empfehlen - vor/nachteil?
            Ich denke das Gröbste wurde hier bereits genannt: Probleme mit der Auto-Vervollständigung von IDEs, Code-Coverage Tools, Dokumentation - vs - Ersparnis beim Tippen. Letzteres leisten auch Code-Generatoren (in diesem Fall speziell für Getter & Setter) ohne dass man dabei auf ein gutes Klassen-Design verzichten muss.

            Zitat von helpmeplease Beitrag anzeigen
            wo ich mir auch immer schwer tue ist die notwendigen klassen zu definieren - also für was braucht es alles eine eigene klasse, was packt man in eine klasse etc. - gibt es da einen tip wie man da am besten die struktur aufbaut?
            Dafür gibt es keine goldene Regel, aber bewährte Prinzipien an die man sich halten sollte. Wenn du dich noch an dem Punkt befindest, an dem es dir schwer fällt Klassen und deren Zuständigkeiten zu definieren, solltest du vielleicht mal einen Blick auf folgendes Dokument werfen: SOLID. Im Idealfall löst eine Klasse exakt ein Problem.

            Zitat von helpmeplease Beitrag anzeigen
            geht das wirklich nur über erfahrung oder kann man sich da an einem gewissen leitfaden orientieren das man da nicht unnötig viele klassen generiert aber auch nicht zu viel logik nur in eine klasse packt ...
            Erfahrung ist natürlich wichtig, meiner Meinung nach sogar unumgänglich. Ein sehr wichtiger Lernfaktor ist hierbei das Studieren von Quellcode bestehender (Open-Source) Projekte. Dabei stößt man oftmals auf interessante Techniken und gewinnt neue Erkenntnisse die sich gerne mal für eigene Projekte nutzen lassen. Ein solides Fundament rund um das Thema OOP / OOD ist natürlich erstrebenswert.

            Viele Grüße,
            lotti
            [SIZE="1"]Atwood's Law: any application that can be written in JavaScript, will eventually be written in JavaScript.[/SIZE]

            Kommentar


            • #7
              Zitat von helpmeplease Beitrag anzeigen
              also macht es schon sinn die eigenschaften in ein array zu packen oder würdet ihr das so nicht empfehlen - vor/nachteil?

              wo ich mir auch immer schwer tue ist die notwendigen klassen zu definieren - also für was braucht es alles eine eigene klasse, was packt man in eine klasse etc. - gibt es da einen tip wie man da am besten die struktur aufbaut?

              geht das wirklich nur über erfahrung oder kann man sich da an einem gewissen leitfaden orientieren das man da nicht unnötig viele klassen generiert aber auch nicht zu viel logik nur in eine klasse packt ...
              Da gibt es viele Leitfäden.

              Du musst die Frage auch andersherum stellen: Was kann man nicht als Objekt abbilden.

              Objektorientierung ist an sich einfach. Stell dir deine Applikation als großes und komplexes Unternehmen vor. Alles was dort passiert, wird von Personen ausgeführt, die im Idealfall genau nur eine Zuständigkeit haben, und über sehr rudimentäre Kommunikationsmittel verfügen, um miteinander zu kommunizieren. Dann gibt es verschiedene Management-Ebenen, die nichts anderes machen, als Informationen zu verteilen und Ergebnisse zu bewerten und in irgendeiner Form zu berichten. Die einzelnen Arbeiter haben dann sehr einfache aber effektive Arbeitsschritte.

              Grundsätzlich gilt:
              • Je weniger eine Klasse kann, oder besser: je weniger Gründe es gibt eine Klasse zu ändern, desto besser.
              • Je weniger sich eine Klasse auf einen genauen Anwendungsfall beschränkt, oder besser: je allgemeingültiger der Lösungsansatz der Klasse für eine Problemdomäne ist, desto besser.


              Eine Klasse ist nur die Blaupause eines Objekts. Sie klassifiziert etwas und versucht damit etwas auf möglichst allgemeingültige Weise zu beschreiben – verlässt dabei aber die Grenzen der Problemdomäne nicht. Wenn du einen Onlineshop entwickeln willst, dann dreht sich dein Hauptaugenmerk um die Darstellung eines Produkts im Kontext des Verkaufs. Als hat ein Produkt einen Endpreis, vielleicht eine Unverbindliche Preisempfehlung und einen Bezugspreis. Wenn du ein Produkt herstellst, dann sind andere Attribute für dich von Belang. Die Allgemeingültigkeit sagt hier also, dass deine Klasse Produkt alles abzudecken versucht, was im Kontext deines Onlineshops als Produkt klassifiziert werden kann. Du solltest nicht eigene Blaupausen für verschiedene Produktgruppen wie Lampen, Staubsauger, Textilien, Elektronik oder Hygieneartikel bauen, obwohl diese Produktgruppen zum Teil arg unterschiedliche Eigenschaften haben. Eine Klasse ist sinnvollerweise (aber nicht zwangsläufig) immer ein Ding, ein Sachverhalt, eine Gegebenheit. Es steht für etwas, tut etwas und weiß etwas. Danach sollte es dann auch benannt werden. Ein Produkt, ein Warenkorb, eine Bestellung, ein Kunde, eine Kundengruppe, etc.

              Ein Objekt auf der anderen Seite ist immer eine Instanz von etwas. Also der konkrete Staubsauger mit Artikelnummer X, die konkrete Bestellung mit Bestellnummer Y oder der Kunde mit Kundennummer Z.

              Ein kurzes Wort zu Singleton
              Es wird dir nicht immer leicht fallen, zwischen Dingen zu unterscheiden, die du applikationsweit in vielen Instanzen, oder in nur einer einzigen Instanz (Singleton) benötigst. Am Anfang ist es nicht verkehrt, erst mal alles als Instanz zu führen und zu versuchen, das Singleton-Pattern komplett zu ignorieren. Der Vorteil von Singleton ist, dass du überall in deiner Applikation einen Zugriff auf ein bestimmtes, einzigartiges Objekt hast.
              Dieser Vorteil wird aber auch schnell zu einem Nachteil. Dadurch, dass du in deinen Objekten fest auf ein bestimmtes Objekt(=Klasse) zugreifst, bist du nicht mehr so leicht in der Lage, deine einmal erstellte Lösung in anderen Situationen wiederzuverwenden (z.B. Schnittstellen zum Onlineshop als eigene, getrennt wartbare Umgebung) und bist schneller genötigt, eine einmal erstellte Lösung noch mal zu implementieren. Die Lösung des Problems heißt DependencyInjection. Du führst Klassen die Abhängigkeit zu anderen Objekten (also das, was du vorher über Singleton gemacht hast) über den Konstruktor zu. Das ist ein wenig mehr Arbeit, als über Singleton auf etwas zuzugreifen, hat aber schnell in einer wachsenden Applikation große Vorteile. Ein weiterer Vorteil ist, dass du nicht mehr gegen konkrete Objekte entwickelst, sondern gegen Interfaces.
              Ein Interface ist wie ein Vertrag, der nur regelt, wie man mit etwas kommunizierst. Wenn du ein Objekt baust, dass eine Lösung gegen ein bestimmtes Interface bereitstellt, dann kannst du verschiedene Implementationen gegen diese Lösung einsetzen.
              Einfaches Beispiel: Du hast eine Testumgebung, wo du die Funktionsfähigkeit eines Objekt mit unechten Komponenten testest, die zwar das gleiche Interface haben, aber mit Laborwerten antworten. Oder eine Komponente, die mit einem Restbasierten Service sprechen soll. Ein DIC wie PHP-DI hilft dir dabei, das Abhängigkeitsmanagement zu automatisieren.

              Dann noch ein paar grundlegende Empfehlungen:
              - Schau dir die SOLID-Prinzipien genau an.
              - Schau dir die DesignPattern der GangOfFour an.
              - Schau dir PHP-Best-Practices an.
              - Versuche ohne static auszukommen.
              - Nutze keine Funktionen.
              - Nutze für Klasseneigenschaften kein protected, außer du kannst es gut begründen. Aber auch dann nicht.

              Kommentar


              • #8
                @rkr,

                Nutze für Klasseneigenschaften kein protected, außer du kannst es gut begründen. Aber auch dann nicht.
                Vorweg: ich habe keine Lust, jetzt ne private-vs-protected Diskussion vom Zaun zu brechen.

                Ich bin zwar sicher nicht so erfahren wie du, aber ich frage mich doch nach dem Sinn dahinter.
                Ich meine, selbst Symfony nutzt an den meisten Stelle protected an Stelle von private, eben mit dem Argument, dass bestimmte Komponenten auch für Sub-Komponenten zugänglich sein sollten.

                PHP-Code:
                class FooRepository implements FooRepositoryInterface {
                    
                /**
                     * @var \Doctrine\DBAL\Connection
                     */
                    
                protected $connection;

                // other stuff

                Wäre es hier nicht vorteilhaft, protected zu nutzen?
                Wenn ich FooRepository erweitere, dann kann die sub-klasse auch gleich das Connection Objekt nutzen, oder?

                LG
                https://github.com/Ma27
                Javascript Logic is funny:
                [] + [] => "", [] + {} => object, {} + [] => 0, {} + {} => NaN

                Kommentar


                • #9
                  Wenn ich eine Eigenschaft auf protected setze, dann können ableitende Klassen damit machen, was sie wollen. Sie setzen damit auch auf das Vorhandensein dieser Eigenschaft. Das bedeutet dann auch, dass ich nicht mehr so flexibel die Datenhaltung meiner Klasse verändern kann, sondern immer noch Rücksicht auf ableitende Komponenten nehmen muss. Ich kann auch nicht einschränken, dass ein nur-lesender Zugriff möglich sein soll. Das ist schon recht dogmatisch, gebe ich zu. Für Anfänger macht es aus meiner Sicht aber sinn, wenn man es am Anfang erst mal so macht und später -wenn man es denn besser einschätzen kann- pragmatischer lösen kann.

                  In deinem Codebeispiel kann ich ja einfach mit einem getter an die Daten kommen:

                  PHP-Code:
                  class FooRepository implements FooRepositoryInterface {
                      
                  /**
                       * @var \Doctrine\DBAL\Connection
                       */
                      
                  private $connection;

                      
                  /* other stuff */
                      
                      /**
                       * @return \Doctrine\DBAL\Connection
                       */
                      
                  public function getConnection() {
                          return 
                  $this->connection;
                      }

                  Kommentar


                  • #10
                    ahh, das habe ich tatsächlich nicht bedacht - danke

                    protected methods gehen aber wieder, da bei jenen diese Problem ja nicht existiert
                    https://github.com/Ma27
                    Javascript Logic is funny:
                    [] + [] => "", [] + {} => object, {} + [] => 0, {} + {} => NaN

                    Kommentar


                    • #11
                      @rkr: Du meintest in einem anderen Thread auch mal was von protected Gettern/Settern, die für dich okay sind, für private Eigenschaften, glaube ich.

                      Kommentar


                      • #12
                        Zitat von mermshaus Beitrag anzeigen
                        @rkr: Du meintest in einem anderen Thread auch mal was von protected Gettern/Settern, die für dich okay sind, für private Eigenschaften, glaube ich.
                        Klar, es geht nur um Eigenschaften (properties), nicht um Methoden.

                        Kommentar


                        • #13
                          hi,

                          vielen dank allen die sich hier die zeit genommen haben - sehr interessante beiträge!!

                          Kommentar


                          • #14
                            Zitat von rkr Beitrag anzeigen
                            - Nutze keine Funktionen.
                            Erläuterung?

                            Kommentar


                            • #15
                              Warum sollte ich prozedurale und objektorientierte Programmierung vermischen wollen?

                              Kommentar

                              Lädt...
                              X