2012-01-24 16 views
8

Ho la seguente interfaccia.È un decoratore o un modello di strategia, o nessuno dei due?

PowerSwitch.java

public interface PowerSwitch { 
    public boolean powerOn(); 
    public boolean powerOff(); 
    public boolean isPowerOn(); 
} 

L'interfaccia sopra dovrebbe consistere di un insieme minimo di metodi che qualsiasi altra funzionalità possono essere derivati ​​da, per rendere il più semplice possibile aggiungere implementazioni PowerSwitch aggiuntivi.

vorrei aggiungere funzionalità all'interfaccia PowerSwitch in fase di esecuzione (cosa decoratori fare), creando una classe che detiene una composizione di un'istanza PowerSwitch e aggiunge nuovi metodi, come i due toggleOnOff() metodi sotto. In questo modo ho solo bisogno di implementare i due metodi di commutazione una volta e si applicherà a tutte le implementazioni PowerSwitch.

È considerata una buona/cattiva pratica? Se cattivo, qualche altro consiglio?

In realtà non è conforme al modello di decorazione in quanto aggiunge ulteriori metodi. È un modello di strategia o uno schema di composizione? O ha un altro nome di modello? Esiste un "decoratore di interfacce"?

PowerSwitchDecorator.java

public class PowerSwitchDecorator { 
    private PowerSwitch ps; 

    public PowerSwitchDecorator(PowerSwitch ps) { 
     this.ps = ps; 
    } 

    public void toggleOnOff(int millis) throws InterruptedException{ 
     powerOn(); 
     Thread.sleep(millis); 
     powerOff(); 
    } 

    public void toggleOnOff(){ 
    powerOn(); 
    powerOff(); 
    } 

    public boolean powerOn() { 
     return ps.powerOn(); 
    } 

    public boolean powerOff() { 
     return ps.powerOff(); 
    } 

    public boolean isPowerOn() { 
     return ps.isPowerOn(); 
    } 
} 
+5

perché non PowerSwitchDecorator implementare l'interfaccia PowerSwitch? Certamente potrebbe ... – Ani

risposta

3

Questa è una buona pratica nel caso di necessità di migliorare l'istanza PowerSwitch in fase di esecuzione. Vi consiglio di implementare l'interfaccia PowerSwitch nel decoratore. L'altro nome del pattern decorator è il pattern proxy.

È possibile definire i metodi estesi in un'altra interfaccia che estende l'interfaccia PowerSwitch. Ciò eviterà di dipendere dal decoratore quando saranno necessari questi metodi estesi.

L'estensione di una classe è una buona pratica quando è necessario migliorare o ridefinire un comportamento durante la compilazione.

+0

Grazie! Avrò il decoratore implementare l'interfaccia PowerSwitch – etxalpo

0

Sarebbe davvero un decoratore se il decoratore implementasse anche l'interfaccia PowerSwitch. Lo definirei come aggregazione di oggetti.

7

Così com'è, qualsiasi codice che vuole utilizzare i toggleOnOff(int) o toggleOnOff() metodi avrà bisogno di un'istanza di PowerSwitchDecorator, non PowerSwitch. Questo tipo di sconfigge lo scopo di un decoratore che dovrebbe essere trasparente per il cliente.

Se si desidera che tutte le implementazioni abbiano questi metodi, è necessario includerle nell'interfaccia PowerSwitch.

Poi, come suggerisce @Ani, è possibile modificare quanto sopra PowerSwitchDecorator di estendere PowerSwitch modo da poter fare questo:

PowerSwitch switch = new PowerSwitchDecorator(new ConcretePowerSwitch()); 
switch.toggleOnOff(); 

ora avete una variabile di tipo PowerSwitch con funzionalità 's il PowerSwitchDecorator.

MODIFICA: Si noti che è necessario utilizzare un modello stabilito solo se soddisfa le proprie esigenze. Puoi usare l'approccio che hai mostrato se funziona per te. Non è necessario calzare il corno in un modello specifico.

Che tipo di oggetto vuoi passare in giro? Vuoi metodi come questo nel tuo API:

void connect(PowerSwitch powerSwitch, Appliance appliance); 

o metodi come questo:

void connect(PowerSwitchDecorator powerSwitch, Appliance appliance); 

(mi dispiace, non sono molto buoni esempi)

Se si desidera che il primo, quindi tutti dovranno "decorare" manualmente il loro PowerSwitch solo per ottenere un paio di metodi di convenienza. Potrebbe essere conveniente per te ora, ma penso che sarà scomodo per gli utenti del tuo codice e probabilmente non si preoccuperanno di farlo. Se si desidera quest'ultimo, è necessario utilizzare il tipo PowerSwitchDecorator nelle firme dei metodi, il che tende a significare che si tratta sempre di PowerSwitchDecorator s e non grezzo PowerSwitch es.

+1

Ma questo non significa che devo implementare metodi fittizi (toggleOnOff) in tutte le implementazioni di powerswitch? e inoltre, se voglio aggiungere un nuovo metodo più avanti (diciamo toggleOffOn) nel Decorator, devo aggiungerlo nell'interfaccia PowerSwitch e aggiornare tutte le attuali implementazioni PowerSwitch (dato che non verranno più compilate)? Potrebbe anche darsi che io non abbia accesso a tutte le implementazioni di powerSwitch (potrebbe far parte di un'interfaccia di un fornitore di servizi). – etxalpo

+1

Come etxalpo, non sono d'accordo. Semplicemente facendo in modo che il decoratore implementa l'interfaccia decorata, è comunque utile perché tutti i client di un PowerSwitch possono utilizzare un PowerSwitchDecorator. Così come tutti i client di un Reader possono utilizzare BufferedReader in modo trasparente. Ciò non impedisce a BufferedReader di aggiungere i propri metodi (readLine() per esempio) e questo pattern è estremamente utile. –

+0

Sì, è vero. Probabilmente vorrai una classe astratta con metodi di commutazione di base da cui ereditano tutte le tue implementazioni. Quindi se vuoi un modo specifico di attivazione puoi decorarlo. Ho modificato la mia risposta, si spera che sia d'aiuto;) –

0

Non è uno dei motivi.

Un decoratore ha l'intenzione di racchiudere un oggetto ed estendere la funzionalità già esistente rendendo l'interfaccia trasparente per il client. Un BufferedInputstream è un esempio. Si noti che Decorator deve implementare la stessa interfaccia del tipo che si sta avvolgendo.

//Let Type be the interface that both the Decorator and DecoratedClass implements 
Type yourInstance = new Decorator(new DecoratedClass()); 

Nota la differenza dal Proxy-modello, dove l'intento principale è quello di controllare l'accesso ad un oggetto, non necessariamente avvolgendo un altro oggetto. In questo caso, consentirebbe al proxy di implementare la stessa interfaccia.

+0

Intendi "Nota che ..." e "Nota la differenza ..." quando dici "Non quello ..." e "Non la differenza ..."? –

+0

Sì, mi dispiace per l'errore di battitura. Grazie! –

0

Diversi motivi spesso sembrano simili, la differenza sta nell'intento del loro utilizzo. Ecco una discussione più generale su questo argomento: When and How Strategy pattern can be applied instead of decorator pattern?

Con il tuo codice, non c'è ancora alcuna differenza reale. Sembra una strategia, poiché PowerSwitchDecorator sta semplicemente delegando il lavoro (cioè l'algoritmo) a un PowerSwitch. Se questa è la tua intenzione e ci sono alterni PowerSwitch che si alternano in modi diversi, lo schema di strategia è la tua scelta.

Se invece si dispone di un set di pulsanti PowerSwitch, ognuno di questi migliora la commutazione in un modo leggermente (decorando la commutazione) e questi PowerSwitch possono essere nidificati, quindi si sta implementando un decoratore. Come già detto, in questo caso è necessario che i decoratori facciano parte della gerarchia di tipi.

0

Direi che non è uno dei motivi.

motivo decoratore

Il pattern decorator viene utilizzato per estendere il comportamento di un'implementazione esistente. Prendi una finestra grafica come esempio, potresti avere una finestra con barre di scorrimento. Allora si può avere una classe come

public class ScrollBarsWindow : Window 
{ 
    private Window windowToDecorate; 
    public ScrollBarsWindow(Window windowToDecorate) 
    { 
     this.windowToDecorate = windowToDecorate; 
    } 

    public void Draw() 
    { 
     windowToDecorate.Draw(); 
     DrawScrollBars(); 
    } 

    public void DrawScrollBars() 
    { Draw the scroll bars } 
} 

Il modello di strategia

Il modello di strategia è usato per fare cose diverse a seconda della strategia scelta. Diciamo che stai facendo un caffè.La si potrebbe avere qualcosa di simile:

public interface IMakeCoffeeStrategy 
{ 
    public Coffee MakeCoffee(); 
} 

public class CappuccinoStrategy : IMakeCoffeeStrategy 
{ 
    public Coffee MakeCoffee { make your cappuccion } 
} 

public class LatteStrategy : IMakeCoffeeStrategy 
{ 
    public Coffee MakeCoffee { make your latte } 
} 

public class Context 
{ 
    private IMakeCoffeeStrategy strategy; 
    public Context(IMakeCoffeeStrategy strategy) 
    { 
     this.strategy = strategy; 
    } 

    public Coffee MakeSomeCoffee() 
    { 
     return strategy.MakeCoffee(); 
    } 
} 

e utilizzarlo come

public class MyCoffeeMachine 
{ 
    public Coffee MakeCoffee(CoffeeType coffeeType) 
    { 
     if(coffeeType == CoffeeType.Latte) 
      return new Context(new LatteStrategy()).MakeSomeCoffee(); 
     else if(coffeeType == CoffeeType.Cappuccino) 
      return new Context(new CappuccinoStrategy()).MakeSomeCoffee(); 

     ... 
    } 
} 

Leggere i seguenti link per ulteriori informazioni:

0

La tua classe PowerSwitchDecorator non è decoratore. L'implementazione è vicino a Strategy_pattern anche se i comandi assomigliano Command_pattern

In Decorator modello, Decorator in realtà implementa l'interfaccia (cioè Component) e la vostra classe non sta facendo lo stesso.

Dai un'occhiata alla diagramma delle classi

enter image description here

Nel diagramma sopra, Component è un'interfaccia. Decorator implementa l'interfaccia Component e contiene l'interfaccia con Composition. Guarda la variabile membro - component.

riferirsi a queste domande per una migliore comprensione:

Decorator Pattern for IO

Real World Example of the Strategy Pattern

Problemi correlati