Esempio di SOLID Xerox in PHP

4

C'è un buon esempio su Wikipedia per quanto riguarda la violazione dei principi SOLID.

The ISP was first used and formulated by Robert C. Martin while consulting for Xerox. Xerox had created a new printer system that could perform a variety of tasks like stapling a set of printed papers and faxing. The software for this system was created from the ground up and performed its tasks successfully. As the software grew, making modification became more and more difficult so that even the smallest change would take a redeployment cycle of an hour. This was making it near impossible to continue development. The design problem was that one main Job class was used by almost all of the tasks. Anytime a print job or a stapling job had to be done, a call was made to some method in the Job class. This resulted in a huge or 'fat' class with multitudes of methods specific to a variety of different clients. Because of this design, a staple job would know about all the methods of the print job, even though there was no use for them. The solution suggested by Martin is what is called the Interface Segregation Principle today. Applied to the Xerox software, a layer of interfaces between the Job class and all of its clients was added using the Dependency Inversion Principle. Instead of having one large Job class, a Staple Job interface or a Print Job interface was created that would be used by the Staple or Print classes, respectively, calling methods of the Job class. Therefore, one interface was created for each job, which were all implemented by the Job class.

http://en.wikipedia.org/wiki/Interface_segregation_principle

Ho cercato di trovare una buona soluzione PHP per questo, ho ottenuto questo risultato:

 class Job implements StampleJob, PrintJob {
 }

 class Print {
   protected $objPrintJob;
   public function __construct(PrintJob $objPrintJob) {
     $this->objPrintJob = $objPrintJob;
   }
 }

 class Staple {
   protected $objStapleJob;
   public function __construct(StapleJob $objStapleJob) {
     $this->objStapleJob = $objStapleJob;
   }
 }

Posso capire in che modo l'interfaccia limiterà la conoscenza, ma in realtà non cambierà la grande classe Job o rimuoverò la violazione SRP. Puoi chiarire in che modo questa soluzione risolve il problema: "Il problema di progettazione era quello una classe di lavoro principale è stata utilizzata da quasi tutte le attività "?

    
posta danidacar 11.05.2013 - 21:20
fonte

1 risposta

4

In primo luogo, consente di capire qual è stato il problema: Il lavoro Staple conosce molti più metodi che non usa oggi , (ad esempio, il metodo print ) ma che sono disponibili perché lo usi, se lo desidera. Tuttavia, la classe Job " pensa " che la classe Staple sarà "un buon cittadino" e non userà mai il metodo di stampa.

Qui ci sono molti potenziali problemi importanti - Per qualche motivo, il lavoro di pinzatura può iniziare a utilizzare il metodo di stampa, accidentalmente o intenzionalmente.

Quindi lungo la strada, eventuali modifiche al metodo di stampa potrebbero non essere verificate,
OPPURE, qualsiasi modifica al metodo di stampa attiverà un test di regressione anche nel lavoro di pinzatura,
E, qualsiasi analisi di impatto per le modifiche al lavoro di stampa implicherà necessariamente anche l'analisi dell'impatto del lavoro di pinzatura.

Questo è solo il problema di Staple che conosce le funzioni di stampa. Poi c'è il caso del lavoro di stampa che conosce tutto sulle funzioni di graffatura . Gli stessi problemi

Molto presto, questo sistema raggiungerebbe un punto in cui qualsiasi cambiamento richiederà un'analisi completa di impatto di ciascun modulo e un test di regressione completo.

Un altro problema è che oggi , tutti i lavori che possono essere stampati possono essere graffati e viceversa su questa particolare stampante.

Tuttavia, domani, potrebbe essere necessario installare lo stesso firmware su un dispositivo che stampa solo o solo graffette. Cosa poi? Il codice presuppone già che tutti i Lavori siano stampabili e stapleable. Quindi qualsiasi ulteriore ripartizione granulare / semplificazione delle responsabilità è impossibile.

In termini più recenti, immagina una classe chiamata "AppleDevice" che ha funzioni per MakePhoneCall e PlayMusic. Ora il tuo problema è che mentre puoi usare facilmente questo su un iPhone, non puoi usarlo per un iPod poiché l'iPod non può effettuare chiamate telefoniche.

Quindi, il problema è non che la classe Job è onnipotente. In effetti, è così che dovrebbe essere, in modo che possa fungere da collegamento comune nell'intero "flusso di lavoro" in cui qualcuno può eseguire la scansione di un lavoro, quindi stamparlo, quindi graffarlo, ecc. Il problema è che l' utilizzo di tutti i suoi metodi non è limitato. Chiunque e chiunque può utilizzare e abusare di qualsiasi metodo ogni volta che lo desidera, rendendo così la manutenzione difficile.

Quindi, l'approccio Iniezione di dipendenza di dire solo agli utenti "esattamente ciò che devono sapere, e nient'altro" assicura che i moduli di chiamata usino solo il codice che sono destinati a loro. Un'implementazione di esempio dovrebbe essere:

interface IStapleableJob { void stapleYourself(); }
interface IPrintableJob { void printYourself(); }
class Job implements IStapleableJob, IPrintableJob {
....
}

class Staple {
  public static void stapleAllJobs(ArrayList<IStapleableJob> jobs) {
    for(IStapleableJob job : jobs) job.stapleYourself();
  }
}

class Print {
  public static void stapleAllJobs(ArrayList<IPrintableJob> jobs) {
    for(IPrintableJob job : jobs) job.printYourself();
  }
}

Qui, anche se si passa un oggetto Job ai metodi Staple e Print, non sanno sapere che è un lavoro, quindi non possono usare metodi che non dovrebbero. Pertanto, quando si apportano modifiche a un modulo, la portata dell'analisi dell'impatto e dei test di regressione è limitata. Questo è il problema risolto dall'ISP.

    
risposta data 12.05.2013 - 05:13
fonte

Leggi altre domande sui tag