Der zweite Eintrag der „Design Patterns in der Praxis“ Serie ist dem Factory Pattern gewidmet. Bei diesem Entwurfsmuster wird „plump“ formuliert eine Klasse durch die Methode einer anderen Klasse instanziiert.
Natürlich ist das nichts besonderes, doch es kommt -wie so oft- auf den Standpunkt bzw. die Nutzung an.

Stellt euch vor ihr habt einige Datenbank Model-Klassen mit langen Namen wie z.B.

my_database_blog_postings
my_database_blog_types
my_database_blog_comments

Diese Klassen leiten von einer übergeordneten Klasse ab:

database

Implementiert ihr nun eine Factory-Methode in die übergeordnete Klasse würde sich der Code beim instanziieren folgendermaßen ändern:

// So wurden die Klassen bisher instanziiert.
$postings = new my_database_blog_postings();
$types = new my_database_blog_types();

// So könnte es mit Hilfe der Factory-Methode aussehen:
$postiongs = database::factory('postings');
$types = database::factory('types');

Das setzt natürlich voraus das ihr ein einheitliches Namensschema für eure Klassen habt! Ihr könnt natürlich auch ohne ein gleichmäßiges Schema das Factory-Pattern nutzen, jedoch müsstet ihr dann womöglich den vollen Klassen-Namen abtippen – Ohne Autovervollständigung (da es sich um einen String handelt) kann das durchaus nerven kosten und für Fehler sorgen.

Anschließend möchte ich euch zeigen, wie die Factory-Methode aussehen könnte:

// Database Klasse.
class database
{
   protected $prefix = 'my_database_blog_';

   /**
    * Factory Methode.
    *
    * @param   string  $model  Der Name des zu instanziierenden Models.
    * @return  object
    */
   public static function factory($model)
   {
      $classname = $prefix . $model;
      if (class_exists($classname))
      {
         return new $classname();
      }

      // Fehlerausgabe.
   }

   // ...

Für den Fall das eine Klasse nicht existiert könnt ihr eine hübsche Exception werfen! Vor allem Projekte an denen mehrere Personen arbeiten werden ihre Freude damit haben 😉

Die Factory-Methode bietet euch folgende Vorteile

  • Da ihr direkt eine Instanz der Klasse erhaltet könnt ihr sofort auf die Methoden oder Variablen der selbigen zugreifen.
    // Wieder ein Schritt zum "Fluent Interface"...
    $postings = database::factory('postings')->get_all_postings();
  • Durch den Aufruf aller Models mit Hilfe der Factory-Methode könntet ihr Beispielsweise für jedes Model eine Singleton Instanz zurückliefern, sodass ihr eine Klasse nicht mehrmals instanziieren müsst und die Resourcen etwas schont.
  • Außerdem könnt ihr in der Factory-Methode einen Log mitschreiben lassen wann und wie oft ihr auf welche Model-Klassen zugreift um zu späteren Zeitpunkten besser debuggen bzw. nachvollziehen zu können.
  • Wenn ihr das Factory-Pattern für ein bestimmtes Gebiet einsetzt, lassen sich durch die Factory-Methode standardisierte Parameter automatisch an die Konstruktoren übergeben. Wir gehen für das nächste Beispiel davon aus, das die Model-Klassen eine Datenbank-Instanz als Parameter erwarten!
    // Ohne das Factory Pattern müsstet ihr die Parameter immer wieder selbst eintippen:
    $db = database::get_instance();
    $postings = new my_database_blog_postings($db);
    $comments = new my_database_blog_comments($db);
    
    // Das instanziieren der Datenbank lässt sich in die Factory-Methode verschieben.
    $postings = database::factory('posting');
    $comments = database::factory('comments');

Es gibt jedoch auch Nachteile, die nicht außer Acht gelassen werden dürfen

  • Da ihr mit einer einzigen Methode die verschiedensten Klassen-Instanzen zurückliefern könnt wird es eurer IDE in der Regel nicht möglich sein mit Autovervollständigung zu dienen.
    Das soll heißen, wenn ihr in der Klasse my_database_blog_comments eine Methode namens get_all_comments() habt, wird eure IDE diese Methode vermutlich nicht zur Autovervollständigung anbieten. Doch es gibt einen kleinen Trick um eurer IDE auf die Sprünge zu helfen:

    /**
     * Mit diesem PHPDoc kann die IDE erkennen um was es sich bei $comments handelt.
     * @var  my_database_blog_comments
     */
    $comments = database::factory('comments');

    Okay, ja, durch diesen Nachteil fällt mehr Arbeit an als wegfällt – Doch es bleibt schließlich jedem selbst überlassen so penibel zu arbeiten!

Zugegeben, mir fallen keine weiteren Nachteile ein (Wisst ihr welche? Schreibt ein Kommentar!).

Übrigens sollte man das Factory-Pattern nicht dazu missbrauchen um alle Klassen eines Projekts nur noch über diese aufzurufen. Soll heißen: So schön und gut dieses Pattern ist, bitte versucht es nicht zwanghaft überall einzusetzen! Es gibt immer sinnvolle Situationen für solche Konstrukte, doch diese sollten nicht das Design der Applikation beeinflussen sondern lediglich als Helfer dienen.

Ich denke damit werde ich den Heutigen Eintrag beenden. Wir lesen uns hoffentlich nächste Woche zum dritten Teil der Serie wieder! Allen Lesern wünsche ich eine erfolgreiche und produktive Woche – Wie immer freue ich mich über Kommentare und Anregungen!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.

Diese Website verwendet Akismet, um Spam zu reduzieren. Erfahre mehr darüber, wie deine Kommentardaten verarbeitet werden.