2012-11-07 6 views
7

Definicja DI cytowany z Wikipedii stwierdza:Wykonywanie tej klasy są zgodne z zasadą Dependency Inversion

A. moduły wysokiego szczebla nie powinno zależeć od modułów niskopoziomowych. Obie powinny zależeć od abstrakcji. B. Abstrakcje nie powinny zależeć od szczegółów. Szczegóły powinny zależeć od abstrakcji.

Próbuję zastosować tę zasadę do mojego kodu:

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

Teraz ponieważ dlaczego Printer klasa zależy Zend_Log który nie jest ani klasa abstrakcyjna ani interfejsu potem mam naruszenie Dependency Inversion zasada.

Jak mogę to naprawić, wiedząc, że Zend_Log nie rozszerza klasy abstrakcyjnej ani nie implementuje interfejsu?

+3

Ładne pytanie .. –

Odpowiedz

5

Najprostszym sposobem byłoby użycie adaptera interfejsu, np. utworzyć interfejs API, którego powinna używać drukarka w interfejsie, a następnie zaimplementować ten interfejs w adapterze dla składnika Zend_Log. Przełóż betonowy łącznik do drukarki. Drukarka będzie wówczas zależeć od PrinterLog, a nie od konkretnego Zend_Loga.

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

Widzę. Więc owinąłeś 'Zend_Log' i przekazałeś wszystkie wywołania metod do klasy otoki. Pytanie jednak, czy buduję aplikację przy użyciu Zend Framework, czy powinienem zawsze owijać takie klasy biblioteki? klasy takie jak 'Zend_Mail',' Zend_Session', 'Zend_DB', ... itd. muszą być najpierw opakowane przed użyciem ich w moim kodzie? – Songo

+0

Rozumiem, że jest to zasadniczo ten sam wzorzec, ale czy nie jest to przypadek, w którym chcielibyśmy go nazwać proxy (zamiast adaptera), ponieważ nie chcemy zmieniać interfejsu, tylko go streścić? Czy jestem poza bazą? re: http://stackoverflow.com/questions/350404/how-do-the-proxy-decorator-adaptor-and-bridge-patterns-differ – Matthematics

+0

@Songo Jeśli chcesz postępować zgodnie z DIP, to tak. Zaletą jest to, że niższe warstwy można łatwiej wymieniać za pomocą różnych implementacji, co przynosi korzyści w zakresie zmiany i konserwacji. Jednak napisanie tych adapterów wymaga dodatkowego wysiłku. To kompromis i osąd, który musisz zrobić sam. Zobacz także http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html – Gordon

2

Oto nieco alternatywa spojrzenie na samego API .. więc to byłoby Ci standardowy setup:

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 
    } 
} 

I to byłoby loggable drukarka:

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(); 
    } 

} 

Gdzie ten pochodzi z jest następujący przypadek użycia: jeśli w rzeczywistości chcesz zacząć kontrolować korzystanie z prawdziwej drukarki (stażysta znowu był printing out the internet). Wtedy nie zrobiłbyś innej drukarki. Próbowałbyś dodać kontrolę zewnętrzną.

Programowanie to rodzaj związany z Open/closed principle.

Należy pamiętać, że jest to tylko jeden z pomysłów i należy się temu przyjrzeć przed próbą użycia w kodzie produkcyjnym.

Powiązane problemy