2013-10-18 15 views
6

Nel modello di progettazione Decorator abbiamo una ItemClass (p.es. Coffee), quindi un AbstractDecorator (p.e CoffeeDecorator) che contiene un riferimento a Coffee e ConcreteDecorators (come latte). La mia domanda è: perché abbiamo bisogno della classe AbstractDecorator, perché i decoratori di cemento non ereditano direttamente dalla classe Coffee? O perché non abbiamo un'interfaccia che contiene la proprietà ItemClass, se vogliamo già assicurarci che ConcreteDecorators abbia un riferimento a ItemClass? Bu usando questo AbstractDecorator stiamo solo disabilitando un'opzione che i nostri ConcreteDecorator ereditano un'altra classe. Grazie in anticipo!Uso della classe Decorator astratta nel pattern Decorator

risposta

1

Utilizziamo classi astratte per rimuovere la duplicazione dalle classi concrete. Nel modello decoratore si ha la duplicazione di memorizzare l'istanza dell'oggetto decorato e le chiamate di passaggio ad esso. Se non si sposta questa logica al decoratore di base (astratto), sarà necessario implementarlo in ogni decoratore concreto.


consideri seguente interfaccia bevande:

public interface IBeverage 
{ 
    decimal Price { get; } 
    string Description { get; } 
} 

che viene realizzato tramite il caffè:

public class Coffee : IBeverage 
{ 
    public decimal Price 
    { 
     get { return 3.5M; } 
    } 

    public string Description 
    { 
     get { return "Coffee"; } 
    } 
} 

Ora si desidera creare prima decorator per il caffè. Non è necessario creare un decoratore astratto in questo momento. Lascia che il nostro latte sia gratis. Basta scrivere il codice più semplice di cui hai bisogno:

public class Milk : IBeverage 
{ 
    private readonly IBeverage _beverage; 

    public Milk(IBeverage beverage) 
    { 
     _beverage = beverage; 
    } 

    public decimal Price 
    { 
     get { return _beverage.Price; } // price not changed 
    } 

    public string Description 
    { 
     get { return _beverage.Description + " with milk"; } 
    } 
} 

Ora hai bisogno di un altro decoratore. Let it be cream:

public class Cream : IBeverage 
{ 
    private readonly IBeverage _beverage; 

    public Cream(IBeverage beverage) 
    { 
     _beverage = beverage; 
    } 

    public decimal Price 
    { 
     get { return _beverage.Price + 2M; } 
    } 

    public string Description 
    { 
     get { return _beverage.Description + " with cream"; } 
    } 
} 

È possibile visualizzare il codice duplicato. Quindi, è tempo di refactoring. Passiamo codice duplicato basare classe decoratrice astratta, che la responsabilità sarà in possesso di riferimento a bevande decorato e passando le chiamate ad esso:

public abstract class BeverageDecorator : IBeverage 
{ 
    private readonly IBeverage _beverage; 

    public BeverageDecorator(IBeverage beverage) 
    { 
     _beverage = beverage; 
    } 

    public virtual decimal Price 
    { 
     get { return _beverage.Price; } 
    } 

    public virtual string Description 
    { 
     get { return _beverage.Description; } 
    } 
} 

Ora è possibile ignorare solo le chiamate che comportamento è cambiato dal vostro decoratore. Il decoratore di latte avrà il seguente aspetto:

public class Milk : BeverageDecorator 
{ 
    public Milk(IBeverage beverage) 
     : base(beverage) 
    { 
    } 

    public override string Description 
    { 
     get 
     { 
      return base.Description + " with milk"; 
     } 
    } 
} 

Molto più pulito, sì? Ecco perché utilizziamo il decoratore di base.

+0

Ok, sono d'accordo. Ma non è un piccolo prezzo da pagare, se ora hai il lusso che il tuo decoratore concreto possa implementare qualche altra classe se necessario? Sto ancora cercando di ottenere questo schema giusto, quindi forse mi manchi qualcosa? – Marko

+1

Ok, ora mentre guardo il tuo codice mi sono reso conto che c'è più vantaggio che impostare un riferimento ad un oggetto da decorare ... In questo modo incapsula tutto il comportamento che è lo stesso per i tuoi decoratori concreti. Ma ancora, c'è una voce nella mia testa che dice che sarebbe bello se tu potessi rendere i decoratori in cemento aperti per l'implementazione ... :) – Marko

+1

@breakpoint scusa, non ho avuto il problema. La duplicazione è sempre malvagia, quindi devi evitarlo. Non sei obbligato ad ereditare TUTTI i decoratori dal decoratore astratto. Se uno dei decoratori concreti dovrebbe implementare qualche altra classe, ereditarlo da quell'altra classe e implementare direttamente IBeverage. BTW è un requisito molto strano, da ereditare da qualche altra classe. Considera di utilizzare la composizione anziché l'ereditarietà in questo caso. –

Problemi correlati