Die Statik ist schlecht, aber was ist mit dem Factory-Muster?

13

Ich bin in einem TDD-Projekt und versuche, mich so gut wie möglich an die guten Praktiken zu halten, die mit dieser Art von Entwicklung verbunden sind. Einer von ihnen vermeidet so viel wie möglich statisch und global.

Ich stehe vor diesem Problem: Ich habe ein Objekt "Artikel", mit dem "Optionen" (zusätzliche "Mikroartikel") verknüpft sein können.

Ich kann nicht herausfinden, wie man einen guten Ansatz verfolgt, der nicht kontraproduktiv ist oder zu viele Abfragen erzeugt, da ich in einer Situation wäre, in der alles so entkoppelt ist, dass ich im Grunde 1 Abfrage pro Objekt durchführen muss.

Aus meiner Sicht sehe ich 3 Möglichkeiten:

1) Build inside Artikel:

class Article
{
    //[...]
    public function getArrOption(){
        //Build an array of Options instance.
        //return an array of Options.
    }
}

Pro: Geradlinig

Const: Maintenability: Das Artikelobjekt enthält jetzt die Erstellungslogik für das Option-Objekt. Dies wird wahrscheinlich zu einer Code-Duplizierung führen.

2) Verwenden einer optionFactory

class Article
{
    //[...]
    public function getArrOption(){
        return OptionFactory::buildFromArticleId($this->getId());
    }
}

Pro: Gebäudelogik gehört nicht zur Klasse Artikel

Const: Ich verstoße gegen die Regel "Statisch ist schwer zu verspotten", was es schwierig macht, meine Artikelklasse zu testen.

3) Trennen Sie alle Logiken.

//Build the array of Option instance in a controller somewhere, using a Factory:
$arrOption = OptionFactory::buildFromArticleId($article->getId());

Pro: Article kümmert sich nur um seine eigene Verantwortung und kümmert sich nicht um seinen "Vater" -Link zu den Optionen. Die Dinge sind wirklich entkoppelt

Const: Benötigt mehr Code im Controller, wenn ich auf die Optionen zugreifen muss. Das heißt, ich sollte niemals eine Fabrik in einem Objekt benutzen, und das klingt für mich irgendwie utopisch ...

Was ist der beste Weg? (Habe ich etwas verpasst?) Danke.

Bearbeiten:

Ganz zu schweigen davon, dass ich, wenn ich Factory Inside Class nicht anrufen kann, grundsätzlich auch nie das Lazy Initialization Pattern verwenden kann ...

FMaz008
quelle
Ich bin mir nicht sicher, ob es relevant ist, aber ich programmiere in PHP, sodass die "Anwendung" weniger Status hat. Wir müssen alle Daten zwischen den einzelnen Seiten neu laden, wenn sie nicht in einem Sitzungscookie gespeichert sind. Das bedeutet , dass wir nicht können Last vor allem wie in einer Anwendungssprache.
FMaz008
@job: Nun, das liegt daran, dass ein statischer Aufruf innerhalb einer Methode beim Unit-Test meist nicht zu ersetzen ist. Das Ziel ist die Verwendung der Abhängigkeitsinjektion. Eine Fabrik ist jedoch normalerweise statisch, sodass sie nicht injiziert werden kann.
FMaz008

Antworten:

12
  1. Static ist nicht "schlecht", es ist nicht verspottbar. Sie können es weiterhin verwenden, wenn das Verspotten keinen Sinn ergibt.

  2. Das ist kein Factory-Muster, es sieht aus wie ein Repository-Muster, obwohl es vielleicht nicht so ist. In Factory haben Sie mehrere Klassen mit derselben Schnittstelle / Basisklasse und möchten die Logik herausfiltern, die entscheidet, welche Klasse zurückgegeben wird. Das Repository ruft die Daten aus seinem Repository ab und abstrahiert die Implementierung dieses Repositorys (der Artikel muss nicht wissen, ob seine Optionen in derselben Datenbank gespeichert sind, in einer anderen, einer XML-Datei, einer CSV-Datei usw.).

  3. Sie haben die Möglichkeit ignoriert, der Article-Klasse ein ObjectFactory-Objekt (oder ein Repository-Objekt oder was auch immer) im Konstruktor zuzuweisen, für das die buildFromArticle-Methode aufgerufen werden kann.

Mein PHP ist verrostet, aber ich denke, es sieht so aus:

class Article
{
    private $_option_repository;

    public function __construct($option_repository) {
        $_option_repository = $option_repository;
    }

    //[...]

    public function getArrOption(){
        return $_option_repository->buildFromArticleId($this->getId());
    }
}

Ich denke, das erfüllt alle Ihre oben genannten Profis.

pdr
quelle
Es ist also in Ordnung, Instanzen von Factory / Repository / Mapper zu haben? Ich brauche einen Abhängigkeitscontainer oder so, denn wenn wir die gesamte Factory / das Repository / den Mapper für alle möglichen Objekte einschleusen müssen, die von einem Objekt zurückgegeben werden können, hat das schnell viel gebracht. (Artikel -> Optionsgruppe -> Option -> Artikel usw.)
FMaz008
1
Es ist mehr als in Ordnung, es ist vorzuziehen. Ich behalte mir im Allgemeinen statischen Gebrauch vor, um wiederholten Code zu entfernen, der klein genug ist, um in mehreren Klassen getestet zu werden. Und ja, ein IOC / DI-Container wird Ihnen das Leben erheblich erleichtern. Verwenden Sie eine.
pdr
1

Hier ist ein Zitat aus dem Papier, das besagt, dass Sie niemals statische Methoden benötigen, dass abstrakte Fabriken sich als verwirrend erwiesen haben und dass eine geringfügige Änderung der Sprache in Richtung Abhängigkeitsinjektion als Lösung vorgeschlagen wird.

Die enge Kopplung zwischen Instanzen und ihren Klassen unterbricht die Kapselung und erschwert zusammen mit der globalen Sichtbarkeit statischer Methoden das Testen. Indem wir die Abhängigkeitsinjektion zu einem Merkmal der Programmiersprache machen, können wir statische Methoden insgesamt loswerden. Wir verwenden die folgenden semantischen Änderungen:

(1) Ersetzen Sie jedes Auftreten eines globalen durch einen Zugriff auf eine Instanzvariable.

(2) Lassen Sie diese Instanzvariable automatisch in das Objekt injizieren, wenn es instanziiert wird.

"Seuss: Entkopplung von Verantwortlichkeiten von statischen Methoden für feinkörnige Konfigurierbarkeit"

Wayback Machine Link

nes1983
quelle
3
Während dieser Link die Frage beantworten kann, ist es besser, die wesentlichen Teile der Antwort hier einzuschließen und den Link als Referenz bereitzustellen. Nur-Link-Antworten können ungültig werden, wenn sich die verlinkte Seite ändert.
gnat