2012-11-07 2 views
7

Die Definition von DI aus Wikipedia zitiert heißt es:machen diese Klasse mit dem Prinzip Inversion Abhängigkeit erfüllt

A. High-level-Module nicht auf Low-Level-Module abhängen. Beide sollten von Abstraktionen abhängen. B. Abstraktionen sollten nicht von Details abhängen. Details sollten von Abstraktionen abhängen.

Ich versuche, diesen Grundsatz zu meinen Code anwenden:

class Printer{ 
     private $logger;  
     function __construct(Zend_Log $logger){ 
      $this->logger=$logger; 
     }  
     function print(){ 
      //Some code 
      $this->logger->log('Logger in action ;)'); 
     }   
    } 

Da nun, warum hängt Printer Klasse auf Zend_Log die weder eine abstrakte Klasse ist noch eine Schnittstelle dann bin ich zu verletzen die Abhängigkeit Inversion Prinzip.

Wie kann ich das beheben, wissend, dass Zend_Log keine abstrakte Klasse erweitert noch eine Schnittstelle implementieren?

+3

Schöne Frage .. –

Antwort

5

Der einfachste Ansatz wäre die Verwendung eines Schnittstellenadapters, z. Erstelle die API, die dein Drucker in einer Schnittstelle verwenden soll und implementiere diese Schnittstelle in einen Adapter für die Zend_Log-Komponente. Übergeben Sie den Betonadapter an den Drucker. Der Drucker hängt dann vom PrinterLog und nicht vom konkreten Zend_Log ab. Hier

interface PrinterLog 
{ 
    public function log($whatever); 
} 

class ZendPrinterLogAdapter implements PrinterLog 
{ 
    private $logger; 

    public function __construct(Zend_Log $logger) 
    { 
     $this->logger = $logger 
    } 

    public function log($whatever) 
    { 
     // delegate call to $this->logger 
    } 
} 

class Printer 
{ 
    private $logger; 

    function __construct(PrinterLog $logger) 
    { 
     $this->logger = $logger; 
    } 
} 

$printer = new Printer(new ZendPrinterLogAdapter(new Zend_Log)); 
+0

aah ich sehe. Sie haben also 'Zend_Log' eingepackt und alle Methodenaufrufe über die Wrapper-Klasse delegiert. Eine Frage, wenn ich eine Anwendung mit Zend Framework erstellen sollte sollte ich die Bibliothek Klassen immer so wickeln? Klassen wie 'Zend_Mail',' Zend_Session', 'Zend_DB', ... etc müssen alle zuerst verpackt werden, bevor sie in meinem Code verwendet werden? – Songo

+0

Mir ist klar, es ist im Wesentlichen das gleiche Muster, aber ist das nicht ein Fall, wo wir es einen Proxy (anstelle eines Adapters) nennen möchten, da wir die Schnittstelle nicht ändern wollen, nur abstrahieren? Oder bin ich offline? re: http://stackoverflow.com/questions/350404/how-do-the-proxy-decorator-adaptor-and-bridge-patterns-differ – Matthematics

+0

@Songo Wenn Sie DIP religiös folgen wollen, dann ja. Der Vorteil besteht darin, dass die unteren Schichten leichter mit anderen Implementierungen ausgetauscht werden können, was zu Änderungen und Wartung führt. Es erfordert jedoch zusätzlichen Aufwand, diese Adapter zu schreiben. Es ist ein Kompromiss und ein Urteil, das Sie selbst treffen müssen. Siehe auch http://blog.thlle.com/uncle-bob/2012/08/13/the-clean-architecture.html – Gordon

2

ist etwas alternative Einstellung auf gleiche API .. so würde dies Sie Standard-Setup sein:

interface Printerish // couldn't think of a good ajective 
{ 
    public function print(); 
} 

interface CanLogStuff // couldn't think of a good ajective 
{ 
    public function log($text); 
} 


class Printer implements Printerish 
{ 
    public function print() 
    { 
     // do something 
    } 
} 

Und dies wäre speicherbare Drucker:

class LoggedPrinter implements Printerish 
{ 
    protected $logger; 
    protected $pritner; 

    public function __construct(Printerish $printer, CanLogStuff $logger) 
    { 
     $this->logger = $logger; 
     $this->printer = $printer; 
    } 

    protected function print() 
    { 
     $this->logger('I can print, I can print !!'); 
     $this->printer->print(); 
    } 

} 

Wo diese kommen aus ist der folgende Anwendungsfall: Wenn Sie in der realen Welt anfangen wollen, die Verwendung eines echten Druckers zu steuern (intern war wieder printing out the internet). Dann würdest du keinen anderen Drucker machen. Sie würden versuchen, eine externe Kontrolle hinzuzufügen.

Bei der Programmierung bezieht es sich irgendwie auf Open/closed principle.

Denken Sie daran, dass dies nur eine Idee ist, und Sie sollten sich das genau ansehen, bevor Sie versuchen, es im Produktionscode zu verwenden.