2016-05-30 25 views
5

Sono abbastanza nuovo con i modelli e sto studiando Decorator Pattern per un programma che devo scrivere.Decorator Pattern design

Studiando online, ho trovato un esempio di un modello Decorator (è Java pseudo-codice):

class Solution1 
{ 
    static interface Component 
    { 
     void doStuff(); 
    } 

    static class MyComponent implements Component 
    { 
     public void doStuff() 
     { 
      // ... 
     } 
    } 

    static class ComponentDecorator implements Component // This is the Decorator pattern. 
    { 
     private final Component component; 

     public ComponentDecorator(Component component) 
     { 
      this.component = component; 
     } 

     public void doStuff() 
     { 
      this.component.doStuff(); 
     } 
    } 

    static class ComponentDecorator1 extends ComponentDecorator 
    { 
     public ComponentDecorator1(Component component) 
     { 
      super(component); 
     } 

     private void doExtraStuff1() 
     { 
      // ... 
     } 

     public void doStuff() 
     { 
      super.doStuff(); 
      doExtraStuff1(); 
     } 
    } 

    static class ComponentDecorator2 extends ComponentDecorator 
    { 
     public ComponentDecorator2(Component component) 
     { 
      super(component); 
     } 

     private void doExtraStuff2() 
     { 
      // ... 
     } 

     public void doStuff() 
     { 
      super.doStuff(); 
      doExtraStuff2(); 
     } 
    } 

    public static void main(String[] args) 
    { 
     MyComponent   c = new MyComponent(); 
     ComponentDecorator1 cd1 = new ComponentDecorator1(c); 
     ComponentDecorator2 cd2 = new ComponentDecorator2(cd1); 

     cd2.doStuff(); // Executes Component.doStuff, ComponentDecorator1.doExtraStuff1, ComponentDecorator2.doExtraStuff2 
    } 
}; 

Quando ho analizzato l'esempio, ho capito che in passato ho fatto un modello molto simile ma in modo diverso:

import java.util.*; 

class Solution2 
{ 
    static interface Component 
    { 
     void doStuff(); 
    } 

    static class MyComponent implements Component 
    { 
     public void doStuff() 
     { 
      // ... 
     } 
    } 

    static class ComponentDecorator implements Component // This is NOT the Decorator pattern! 
    { 
     private final List<Component> components = new ArrayList<Component>(); 

     public ComponentDecorator() 
     { 
     } 

     public ComponentDecorator addComponent(Component component) 
     { 
      this.components.add(component); 
      return this; 
     } 

     public void removeComponent(Component component) // Can Decorator do this? 
     { 
      // ... 
     } 

     public void doStuff() 
     { 
      for(Component c : this.components) c.doStuff(); 
     } 
    } 

    static class ComponentDecorator1 implements Component 
    { 
     public ComponentDecorator1() 
     { 
     } 

     private void doExtraStuff1() 
     { 
      // ... 
     } 

     public void doStuff() 
     { 
      doExtraStuff1(); 
     } 
    } 

    static class ComponentDecorator2 implements Component 
    { 
     public ComponentDecorator2() 
     { 
     } 

     private void doExtraStuff2() 
     { 
      // ... 
     } 

     public void doStuff() 
     { 
      doExtraStuff2(); 
     } 
    } 

    public static void main(String[] args) 
    { 
     ComponentDecorator cd = new ComponentDecorator(); 
     cd.addComponent(new MyComponent()); 
     cd.addComponent(new ComponentDecorator1()); 
     cd.addComponent(new ComponentDecorator2()); 

     cd.doStuff(); // Executes MyComponent.doStuff, ComponentDecorator1.doExtraStuff1, ComponentDecorator2.doExtraStuff2 
    } 
} 

a mio parere, il secondo esempio può essere utilizzato in medesime situazioni in cui un pattern Decorator può essere utilizzato, ma è più flessibile (si può, per esempio, rimuovere o riordinare i componenti del lista), quindi le mie domande:

  • La soluzione 1 (modello decoratore corretto) è migliore della soluzione 2? Perché?
  • È possibile aggiungere funzioni per la rimozione di istanze nella soluzione 1?
  • È possibile aggiungere funzioni per riordinare le istanze nella soluzione 1?
+0

è impossibile dire quale sia il migliore perché fanno cose diverse. –

+0

Mi sembra che facciano la stessa cosa. Può essere più preciso? – Carlo

+0

Decorator sta estendendo un'altra implementazione ** avvolgendola ** nel codice di estensione. La tua soluzione chiama solo diverse implementazioni in sequenza. Ecco [la mia risposta su decorator] (http://stackoverflow.com/questions/12379848/decorator-design-pattern-vs- eternity/12379948#12379948). Prova ad implementarlo con l'approccio alternativo che descrivi e vedrai la differenza –

risposta

2

Soluzione 2 è in realtà un mix tra pattern decoratore e pattern composito.

Penso che la soluzione 1 sia migliore della soluzione 2 se quello che vuoi è solo aggiungere un comportamento e usare la soluzione 1 + il modello composito è meglio se hai anche bisogno di usare più oggetti come uno.

come una risposta più generale su come utilizzare questi due modelli di vedere Difference between the Composite Pattern and Decorator Pattern?

Questa è la risposta chiave:

Il composite consente di costruire una struttura gerarchica (come ad esempio un albero di elementi) in un modo che consente al codice esterno di visualizzare l'intera struttura come una singola entità. Quindi l'interfaccia con un'entità foglia è esattamente la stessa dell'entità per un'entità composta. Quindi l'essenza è che tutti gli elementi nella struttura composita hanno la stessa interfaccia anche se alcuni sono nodi foglia e altri sono intere strutture. Le interfacce utente utilizzano spesso questo approccio per consentire una facile composibilità.

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

Il pattern decoratore permette all'entità di contenere completamente un'altra entità modo che utilizzando il decoratore sembra identica alla entità contenuta. Ciò consente al decoratore di modificare il comportamento e/o il contenuto di qualsiasi incapsulamento senza modificare l'aspetto esteriore dell'entità. Ad esempio, è possibile utilizzare un decoratore per aggiungere l'output di registrazione sull'utilizzo dell'elemento contenuto senza modificare alcun comportamento dell'elemento contenuto.

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

1

è la soluzione 1 (corretto Decorator Pattern) meglio di soluzione 2? Perché?

Soluzione 1 è migliore della Soluzione 2. La soluzione 1 segue il design di Gang of 4 così com'è.

Soluzione 1 è

  1. semplice
  2. meno soggetto a errori rispetto alla soluzione 2. L'interessato ha per popolare la lista & chiara la lista dopo l'uso (che non si sta facendo attualmente). Se si utilizza lo stesso decoratore in più thread, è necessario proteggere il codice per la coerenza della memoria.

esempio del mondo reale di VendingMachineDecorator è disponibile al seguente documentazione @

When to Use the Decorator Pattern?

E 'possibile aggiungere funzioni per la rimozione di istanze in soluzione 1?

Sì. È possibile. È necessario aggiungere la funzione di rimozione in Decorator astratto e Decoratori in cemento.

public void removeStuff() 

Si può avere uno sguardo qui sotto domande SE:

How to remove decorated object from Decorator Pattern in Java

Can you remove a decorator?

+0

Gli esempi per la rimozione di un decoratore sono davvero buoni. Dall'altra parte, "La soluzione 1 è migliore della soluzione 2. La soluzione 1 segue il design di Gang of 4 così com'è". non è una risposta. So che la soluzione 1 è migliore, sto chiedendo perché è meglio. Puoi fornire una risposta alla domanda 1? – Carlo

+0

Risposta aggiornata. –