Artikelformat

Das Factory-Pattern

Heute gibt es wieder einen Beitrag aus der Pattern-Kiste. Das Factory-Pattern ist ein netter Helfer, wenn man eine Klasse erzeugen möchte, den Konstruktor aber nicht so direkt nutzen kann oder will. Man erstellt also eine zweite Klasse, die Factory. In dieser Klasse stellt man Methoden bereit, die ein Objekt der ersten Klasse, die man ja eigentlich nutzen will, zurückliefert. Die Methoden können auch statisch sein. Dagegen spricht mE nichts. Jetzt stellt sich die Frage, wann man ein solches Vorgehen nutzen soll.

Ein Beispiel, dass ich hierfür gerne heranziehe, ist der Zugriff auf eine Datenbank. Angenommen man nutzt keinen OR-Mapper, dann ist eine solche Factory eine nette Variante, um Objekte aus der Datenbank auszulesen. In der Factory definiert man sich Methoden, die verschiedene SQL-Queries abbilden. Zum Beispiel getAll() oder findByName(). In diesen Methoden realisiert man den Datenbankzugriff wie man dies herkömmlich kennt und baut die Ergebnisse in Data Access Objects um, die durchaus vollkommen primitiv und frei jeglicher Logik sind bzw. sein dürfen. getAll() würde ein Array von DAOs zurückliefern und dieses kann man dann in einem Templatesystem weiterverwenden.

Der Vorteil ist nun, dass man den DB Zugriff in einer Klasse (nämlich der Factory) kapseln kann. Die restliche Anwendung muss nichts von der Datenbank wissen. In einem privaten Projekt habe ich so 2 Factories, die mir den Zugang zur Datenbank erlauben. Ich bin der Ansicht, dass bei komplexeren Datenbanken-Schemata es natürlich sinn macht Doctrine oder Propel einzusetzen, da man ab einem bestimmten Punkt seinen eigenen OR-Mapper erfindet und das ist nicht sehr pragmatisch.

Natürlich gibt es bei der Factory auch Nachteile. Dazu gehört bspw. die Tatsache, dass man um ein Objekt zu erzeugen 2 Klassen benötigt. Einerseits die Factory und andererseits die Klasse, die von der Factory geliefert werden soll. In einer kleinen überschaubaren Anwendung ist dieser Overhead vertretbar.

Nun ein kleines Beispiel. Hier gibt es eine Klasse Car und eine CarFactory diese kann rote und blaue Autos erzeugen.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Car {
 
    private $color = null;
 
    public function __construct() {
        $this->color = "white";
    }
 
    public function setColor($color) {
        $this->color = $color;
    }
 
    public function getColor() {
        return $this->color;
    }
}

Die Klasse ist sehr übersichtlich. Man kann eine Farbe setzen und diese auslesen. Der Standardwert ist weiß. Die Factory ist ähnlich komplex:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class CarFactory {
 
    private function __construct() {
 
    }
 
    public static function getBlueCar() {
        return self::getCar("blue");
    }
 
    public static function getRedCar() {
        return self::getCar("red");
    }
 
    private static function getCar($color) {
        $car = new Car();
        $car->setColor($color);
        return $car;
    }
}

Hier gibt es eine Methode für rote Autos, eine für blaue und damit man den Code nicht dupliziert eine private Methode, die die eigentliche Erzeugung durchführt. Nutzt man diesen Code, dann sieht das zum Beispiel so aus:

1
2
3
4
5
$car1 = CarFactory::getBlueCar();
echo "Car 1 is ".$car1->getColor() ."\n";
 
$car2 = CarFactory::getRedCar();
echo "Car 2 is ".$car2->getColor() ."\n";

Die Ausgabe sieht so aus, wie man es erwarten würde:

1
2
Car 1 is blue
Car 2 is red

Und jetzt kann man die CarFactory erweitern, sodass auch Automarken mit ihren Feinheiten berücksichtigt werden oder ähnliches.

By continuing to use the site, you agree to the use of cookies. more information

The cookie settings on this website are set to "allow cookies" to give you the best browsing experience possible. If you continue to use this website without changing your cookie settings or you click "Accept" below then you are consenting to this.

Close