2012-11-07 8 views
7

La definizione di DI citato da Wikipedia afferma: moduli di alto livelloRendere questa classe sia conforme al principio di inversione di dipendenza

A. non dovrebbero dipendere da moduli di basso livello. Entrambi dovrebbero dipendere dalle astrazioni. B. Le astrazioni non dovrebbero dipendere dai dettagli. I dettagli dovrebbero dipendere dalle astrazioni.

Sto cercando di applicare questo principio al mio codice:

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

Ora, poiché il motivo per cui Printer classe dipende Zend_Log che non è né una classe astratta né un'interfaccia poi sto violando l'inversione di dipendenza principio.

Come posso risolvere che sapendo che Zend_Log non si estende una classe astratta né implementare un'interfaccia?

+3

Bella domanda .. –

risposta

5

L'approccio più semplice sarebbe utilizzare un adattatore di interfaccia, ad es. creare l'API che la stampante deve utilizzare in un'interfaccia e quindi implementare tale interfaccia in un adattatore per il componente Zend_Log. Passa l'adattatore concreto alla stampante. La stampante quindi dipenderà dal PrinterLog e non dal concreto Zend_Log.

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 vedo. Quindi hai spostato 'Zend_Log' e delegato tutte le chiamate di metodo a attraverso la classe wrapper. Una domanda però se sto costruendo un'applicazione utilizzando Zend framework devo sempre avvolgere le classi della libreria in questo modo? classi come 'Zend_Mail',' Zend_Session', 'Zend_DB', ... ecc. devono essere tutte incapsulate prima di usarle nel mio codice? – Songo

+0

Mi rendo conto che è essenzialmente lo stesso schema, ma non è questo il caso in cui dovremmo chiamarlo un Proxy (invece di un Adattatore) poiché non vogliamo cambiare l'interfaccia, basta astrarla? O sono fuori base? re: http://stackoverflow.com/questions/350404/how-do-the-proxy-decorator-adaptor-and-bridge-patterns-differ – Matthematics

+0

@Songo Se vuoi seguire DIP religiosamente, allora sì. Il vantaggio è che gli strati inferiori possono essere più facilmente sostituiti con diverse implementazioni, a vantaggio dei cambiamenti e della manutenzione. Tuttavia, ci vuole uno sforzo extra per scrivere quegli adattatori. È un compromesso e un giudizio che devi fare da solo. Vedi anche http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html – Gordon

2

Qui è prendere un po 'alternativo sulla stessa API .. quindi questo sarebbe si configurazione standard:

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

E questo sarebbe stampante loggable:

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

} 

dove questo proviene da è il seguente caso d'uso: se nel mondo reale si desidera iniziare a controllare l'uso di una stampante reale (stagista è stato nuovamente printing out the internet). Quindi non faresti una stampante diversa. Dovresti provare ad aggiungere un controllo esterno.

In programmazione si riferisce a Open/closed principle.

Tenete a mente che questa è solo un'idea e uno dovrebbe prendere uno sguardo duro a questo prima di tentare di utilizzare nel codice di produzione.

Problemi correlati