Ankündigung

Einklappen
Keine Ankündigung bisher.

Verständnis: Design Patterns, Factorys, Singletons u. byRef

Einklappen

Neue Werbung 2019

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

  • #16
    Ich hätte noch eine Frage bezüglich Referenzen und Factory's

    Ich hab folgende Factory:
    PHP-Code:
    <?php
    $db 
    = & DBFactory::create('mysql');

    echo 
    $db->foo;

    class 
    DBFactory
    {
        public static function 
    create($type
        {
            
    $instance NULL;
            switch (
    $type)
            {
                case 
    'mysql':
                    
    $instance = & new MySQL();
                    break;
            }
            
            return 
    $instance;
        }
    }

    class 
    MySQL
    {
        public 
    $foo "Hallo Welt";
    }
    ?>
    Wo sollte der Referenzoperator überall stehen theroretisch würde doch reichen

    PHP-Code:
    <?php
    $db 
    = & DBFactory::create('mysql');
    // restlicher Code wie im Beispiel oben
                    
    $instance = new MySQL();
    // restlicher Code wie im Beispiel oben
    ?>
    oder liege ich da Falsch?
    Gewisse Dinge behält man besser für sich, z.B. das man gewisse Dinge für sich behält.

    Kommentar


    • #17
      Hi.

      In PHP5 werden Referenzen implizit übergeben. Du kannst dir das Kaufmanns-Und also sparen. Allerdings wäre es wahrscheinlich sinnig, $instance als statische Variable zu definieren und vor dem Neubau des jeeiligen Objektes zu prüfen, ob nicht bereits eine nstanz existiert. Wenn mehrere Datenbanken Anwendung finden sollen, dann ist hier auch ein Array angebracht:
      PHP-Code:
      <?php
      class DBFactory()
      {
          private static 
      $aInstances = array();

          public static function 
      create($sType)
          {
              if (!isset(
      self::$aInstances[$sType])) {
                  
      $self::$aInstances[$sType] = new $sType();
                  
      // ...und der ganze Kram, zum Initialisieren
                  // des DBObjektes - der den Einsatz einer 
                  // "DBFactory" ueberhaupt erst rechtfertigt.
              
      }
               return 
      self::$aInstances[$sType];
          }
      }
      ?>
      Basti

      Kommentar


      • #18
        Zitat von Basti
        Allerdings wäre es wahrscheinlich sinnig, $instance als statische Variable zu definieren und vor dem Neubau des jeeiligen Objektes zu prüfen, ob nicht bereits eine nstanz existiert.
        Kommt drauf an wenn du nur mit einer Verbindung pro DBType arbeiten möchtest ist das mit Sicherheit sinnig... aber ansonsten würde das meiner Meinung nach Globals gleichkommen

        PHP-Code:
        <?php
        // ...und der ganze Kram, zum Initialisieren
                    // des DBObjektes - der den Einsatz einer 
                    // "DBFactory" ueberhaupt erst rechtfertigt.
        ?>
        hmmm .... da gehen die Meinungen wohl auseinander ... die Idee die dahinter steckt ist doch gerade die Wiederverwendbarkeit bei einer Umstellung von zb. MySQL auf Oracle
        Gewisse Dinge behält man besser für sich, z.B. das man gewisse Dinge für sich behält.

        Kommentar


        • #19
          Hi.

          Wenn keine Referenzen in der Fabrik gehalten werden sollen und der Code möglichst wiederverwertbar sein soll, dann müssen die erzeugten Objekte auch über eine gleiche Schnittstelle verfügen. Und da würde sich ein einfacher Wrapper doch eher anbieten, als eine Fabrik.

          Beziehungsweise, wenn es keinen "Datenbankspezifischen" Code in der DBFactory gibt, baruchst du keine DBFactory. Dann kannst du auch einfach, im Falle vom Wunsch nach in der Anwendung einmaligen Objeten diese einmal bauen und in ein Registry-Objekt packen, von wo aus es abgeholt werden kann (oder eben Globals *g). Oder auch eben von einer allgemeinen Fabrik erzeugen lassen, die dann garnichts Datenbank-spezifisches enthält und dir jedes Objekt zusamenbastelt und zurückschmeist. Ein Kompromiss wäre Folgendes:
          PHP-Code:
          <?php
          class Factory()
          {
              private 
          $aInstances = array();

              public function 
          __construct(Registry $Registry);

              public function 
          create($sClassName$bExclusive true)
              {
                  if (
          $bExclusive)
                      return new 
          $sClassName($this->Registry);

                  if (!isset(
          $this->aInstances[$sClassName]))
                      
          $this->aInstance[$sClassName] = new $sClasName($this->Registry);

                  return 
          $this->aInstances[$sClassName];
              }
          }
          ?>
          Hier könnte man nach dem Bauen der Objekte noch ein $this->init() einfügen, dass dann von abgeleiteten Fabrik-Klassen überschrieben werden kann, dass dann eben tut, was für das Erzeugen der Gruppe von Objekten, die die abgeleitete Fabrik erzeugen kann notwendig bzw. spezifisch ist.

          Basti

          Kommentar


          • #20
            Naja mir will noch nicht so richtig der Sinn der statischen Instance Variable innerhalb der Factory in den Kopf ... viele sagen hier das es besser ist eine Referenz im Constructor zu übergeben ... wenn ich aber nun diese Statische Instanzierungsmethode der Factory habe brauche ich doch keine Referenz mehr im Constructor ... statische Klassenmethoden kann ich doch ohne weiteres in ner anderen Klasse aufrufen.

            Aber ich denke da gehen die Meinungen wieder einmal stark auseinander und es liegt im Endeffekt am persönlichen Coding-Style wie man das löst...
            Gewisse Dinge behält man besser für sich, z.B. das man gewisse Dinge für sich behält.

            Kommentar


            • #21
              Ich könnte mir die z.b. vorstellen, wenn du ein cms system auf modulbasis baust. Für jedes Modul gibts dann ne Klasse, die auf ein Interface für Module zugrieft. Damit kannst du direkt vorschreiben, dass es z.b. die Funktion "show()" oder "load()" oder wie auch immer gibt...

              Kommentar


              • #22
                äh, @basti, die funktion ist ja schön und gut, aber was machst du, wenn du plötzlich unterklassen brauchst? im endeffekt ist eine Abstract Factory oder Factory nur dann gut, wenn der 'klient' nicht zu wissen braucht, was für eine klasse es zurückbekommt - es verlässt sich auf die oberklasse.

                beispiel: für eine einfache klassenhierarchie:
                PHP-Code:
                Hello  (interface)
                |
                _HelloWorld  (implements Hello)
                   |--- 
                extHelloWorld (extends HelloWorld
                |
                _HelloAnother (implements Hello
                ... und dann hat man eine factory, die etwas zurückgibt:

                PHP-Code:
                class Factory {
                 public function 
                getHello() {
                         return new 
                HelloAnother();
                  }

                der vorteil an factories ist nun, dass die _factory_ entscheidet, was für eine subklasse sie zurückgibt. natürlich kann sie auch entscheiden, ob sie nur ein objekt erzeugt und dieses immer wieder zurückgibt, ob sie das objekt einmal erzeugt und dann prototypisch klont, das ding vorher durch irgendwas durchjagt oder was auch immer:

                der echte 'knackpunkt' an der geschichte ist, dass - solange die 'klienten' nur die factory-methode kennen, sie gar nicht wissen, was für eine konkrete unterklasse sie bekommen. das bestimmt die factory-methode. einzig und allein das wissen die klienten garantiert : dass sie irgend ein objekt bekommen, das das Interface der 'Hello' implementiert.

                und damit hast du innerhalb der factory die möglichkeit, sogar zur laufzeit (was für 'kompilierbare' sprachen wichtig ist), eine klasse im kompletten system auszutauschen, ohne dass die klienten sich darüber beschweren können.

                deine funktion sieht zwar schön aus, unterstützt das ganze aber nicht - denn die klienten müssen immer noch wissen, was für eine klasse sie zurückbekommen wollen - schließlich müssen sie den namen als parameter übergeben.

                sowas nennt sich übrigens abstrakte kopplung, ist zugegebenermaßen nicht gleich von anfang an zu verstehen, es ist aber wunderbar, wenn man's mal verstanden hat.

                Kommentar


                • #23
                  Wo liegt denn das Problem?

                  Jetzt packst du einfach in ene XML-Datei oder sonsowohin die Information, welche konkrete Klasse welche Interface-Anfrage bedienen soll und gibst einfach ein entsprechendes Objekt zurück. Natürlich kannst du auch für jedes Interface eine eigene Fabrik bauen. Aber dort, wo dieser Vorgang immer gleich ist (Interface wird angefragt, Information, welche Klasse eingebunden werden sol liegt dort, Objekt bauen und zurückgeben), kann man das doch zusammenfassen, oder was spricht dagegen?

                  Ich hatte diese Diskussion übrigends mal vor knappen zwei Jahren auf der dclp[1]. Da hatte ich aber noch viel weniger Plan von OOP und so haben mir einfach die Worte gefehlt, mich gescheit auszudrücken (ich hoffe, das ist nun besser georden *g) und so wurde das ein ziemlich verkonteter (aber für mich sehr aufschlußreicher) Austausch.

                  Liebe Grüße,
                  Basti

                  [1] http://groups.google.de/group/de.comp.lang.php.misc/browse_thread/...

                  Kommentar


                  • #24
                    Jetzt packst du einfach in ene XML-Datei oder sonsowohin die Information, welche konkrete Klasse welche Interface-Anfrage bedienen soll und gibst einfach ein entsprechendes Objekt zurück
                    Dafür brauchst Du dann aber auch ein lookup (aha, etwas mit Information X wird angefordert, also liefere ich ein Y)- eben das, was die factory übernimmt. Wenn Du jetzt noch eine Schnittstelle benutzt, damit Du den umliegenden Code für die X Ausprägungen auch X mal neuschreiben musst, bist Du ziemlich genau bei einer abstract factory angekommen.

                    Nehmen wir mal als nicht-factory die "alten" Datenbankfunktionen von php. Und da auch erstmal nur Schritt 1, Verbindungsaufbau
                    mysql_connect, pg_connect usw. usw.
                    Du kannst jetzt ein einheitliches aber schnittstellenloses lookup bauen dbconnect('mysql:localhost....')->return mysql_connect('localhost', ....) / dbconnect('pg:localhost...)->return pg_connect('localhost...') usw usw
                    Aber Du kannst das Ergebnis von dbconnect('pg:localhost...) nicht mit mysql_query verwenden, sondern musst wissen, dass es nur in Verbindung mit pg_query o.ä. Sinn macht. Diese Information muss also (unnütz) sichtbar mitgeschleppt werden, obwohl wieder ähnliche Funktionalität abgebildet wird.
                    Wenn Du das jetzt wieder vereinheitlichst (dbquery() analog zu dbconnect()) und irgendwie, irgendwo die entsprechenden Informationen im Rückgabewert von dbconnect() mitführst, dann kannst Du auch gleich (und besser) die factory implentieren.
                    Und dann kommst Du in der Nähe von PDO an.

                    Kommentar


                    • #25
                      Ich verstehe nicht ganz, worauf du hinaus willst. Ist doch klar, dass es nur Sinn macht, die Entscheidung abzugeben, welches konkrete Objekt einem rausgerückt wird, wenn man auch sicher sein kann, dass dieses Objekt dann auch genau die Funktionen bietet, die man erwartet.

                      Und, was die Abstrakte Fabrik angeht, so unterscheidet sich das, was ich hier geschrieben hab einmal darin, dass die Fabrik keine konkreten Fabriken ausliefert, sondern konkrete Produkte und für diese Produkte bzw. Produktgruppen/Funktionalitäten keine eigenen Methoden bereitstellt, sondern diese als Parameter entgegennimmt. Und eben dadurch, dass es keine konreten Fabriken gibt, sondern die Produkte von einer Produktgruppen-Klasse abgeleitet sind, die dann z.B. über Konstruktoren und Dekonstruktoren verfügt, die von der Fabrik explizit aufgerufen werden.

                      Vielleicht vestehe ich deine Kritik oder deine Worte auch einfach noch nicht. Bin da ganz offen für.

                      Basti

                      Kommentar


                      • #26
                        Naja mir will das immer noch nicht ganz einleuchten ... hier mal ein Beispiel für eine Abstrakte Factory
                        http://www.professionelle-softwareen...t-factory.html

                        Die Frage die sich dabei mir auftut warum Abstract ??? Die Factory kann doch genausogut eine normale Klasse sein ...
                        Gewisse Dinge behält man besser für sich, z.B. das man gewisse Dinge für sich behält.

                        Kommentar


                        • #27
                          @Basti: ich verstehe Deine Ausführungen einfach leider nicht. Deshalb weiss ich nicht, was ich drauf antwrten soll und hab's mit einem (neueren) PHP Beispiel versucht

                          Kommentar


                          • #28
                            Jetzt habe ich mir mal die Funktion DBFactory angesehen.
                            Du hast da eine Art singleton template. Also ein allgemeines singleton, dass erst durch eine Ausprägung durch einen Typen Sinn erhält. In Sprachen, die das unterstützen (zB C++), gibst Du den Typ vorher an. Du erhälst eine neue, konkrete Klasse für diesen Typen.
                            Das passiert bei Dir nicht, alle Deine singletons sind gleich, von aussen sogar ununterscheidbar gleich. Die Ausprägung findet erst beim ersten Aufruf von create() statt.

                            Was passiert eigentlich bei
                            PHP-Code:
                            <?php
                            $a 
                            DBFactory()::create('AKlasse');

                            $b DBFactory()::create('BKlasse');
                            ?>
                            Das kann so doch nicht Sinn der Sache sein.

                            Eine Factory hat mehr Freiheiten beim Erstellen des Objekts. Das kann natürlich die einfache,direkte Abbildung wie in Deinem Beispiel sein. Muss es aber eben nicht. Und auch der gleiche Aufruf zweimal hintereinander muss nicht zugesichert das gleiche Objekt liefern. Gleichwertig ja, aber nicht gleich.

                            Und da würde sich ein einfacher Wrapper doch eher anbieten, als eine Fabrik.
                            Das klingt für mich irgendwie nach dem Misverständnis, dass eine Fabrik eine hochkomplizierte, hochkomplexe Angelegenheit ist. Ist sie nicht zwangsläufig. Und alles ist irgendwie "wrapper".
                            Factory unterscheidet sich von der Menge und vom Aufwand her nicht zwangsläufig von Deiner Klasse.
                            PHP-Code:
                            <?php
                            class ImageFactory {
                                public function 
                            create($type) {
                                    switch(
                            $type) {
                                        case 
                            'png':
                                            return new 
                            PNGImage();
                                        default:
                                            throw new 
                            Exception('unknown image type');
                                    }
                                }
                            }

                            $if = new ImageFactory();
                            $img $if->create('png');
                            ?>

                            Kommentar


                            • #29
                              @Bruchpilot ich würde aber in deinen Beispiel lieber ne statische Methode nehmen ne Instanzierung wäre da fehl am Platz zumal du das Objekt direkt wieder zerstören könntes damit du dir nicht den Speicher zumüllst.
                              Gewisse Dinge behält man besser für sich, z.B. das man gewisse Dinge für sich behält.

                              Kommentar


                              • #30
                                Läßt sich dann aber schlecht(er) als Parameter über- oder evtl. sogar mit einer weiteren Hülle umgeben. Wenn diese Hülle wiederum spezifiziert ist (Interface, abstrakte Klasse), dann kommst Du bei den abstrakten Fabriken an.
                                Damit kannst Du die Erstellung der konkreten Objekte noch weiter kontextabhängig machen. Erst aus dem Kontext ergibt sich die genau Art der Erstellung; aber den "verbrauchenden" Teil brauchst Du nicht jeweils anpassen.

                                Kommentar

                                Lädt...
                                X