2011-11-08 33 views
1

我想知道如何將狀態添加到可供用戶使用的裝飾器鏈中。鑑於這個簡化的模型:在修飾器模式中添加狀態

abstract class AbstractPizza{ 
    public abstract print(...); 
} 

class Pizza:AbstractPizza{ 
    public int Size (get; set;) 
    public print(...); 
} 

abstract class AbstractPizzaDecorator{ 
    public Pizza:AbstractPizza; 
    public abstract print(); 
} 

class HotPizzaDecorator:AbstractPizzaDecorator{ 
    public int Hotness (get; set;) 
    public print(...); 
} 

class CheesyPizzaDecorator:AbstractPizzaDecorator{ 
    public string Cheese (get; set;) 
    public print(...); 
} 


void Main() 
{ 
    BigPizza = new Pizza(); 
    BigPizza.Size = 36; 

    HotBigPizza = new HotPizzaDecorator(); 
    HotBigPizza.Pizza = BigPizza; 
    HotBigPizza.Hotness = 3; 

    HotBigCheesyPizza = new CheesyPizzaDecorator(); 
    HotBigCheesyPizza.Pizza = HotBigPizza; 
    HotBigCheesyPizza.Cheese = "Blue"; 

    HotBigCheesyPizza.print(); 
    HotBigCheesyPizza.size = 28; //ERRRRRR !!!!!!!!!!!!!!!!!!!!!!! 
} 

現在,如果他們都實現了打印方法,並通過鏈傳播,這一切都很好。但是這對國家有什麼用?我無法訪問HotBigCheesyPizza上的size屬性。

我失蹤的部分是什麼?錯誤的模式?

感謝您的幫助! Cheers

+0

你將如何建立HotBigCheesyPizza如果您HotPizzaDecorator不接受CheesyPizzaDecorator改寫......你能不能給個例子? –

回答

1

我相信你的組件(Pizza)和你的抽象裝飾器(PizzaDecorator)應該共享相同的接口,這樣裝飾器的每個實例都可以執行與核心組件(Pizza)相同的操作。

+0

這意味着所有的裝飾器實現相同的屬性。我試圖添加狀態。 HotPizzaDecorator不知道尺寸,而CheesyPizza是無知的熱度。 – EasierSaidThanDone

3

裝飾者模式用於向裝飾類添加額外的行爲,而無需客戶端進行調整。因此,它不打算將新界面(例如hotness,cheese)添加到正在裝飾的物件。

它可能用於什麼的一個有點不好的例子是您想要更改size的計算方式:您可以創建一個MetricSizePizzaDecorator,將大小轉換爲/來自英制/公制單位。客戶不會知道披薩已經裝飾 - 它只是調用getSize()並做任何它需要做的結果(例如,計算價格)。

我可能不會在我的例子中使用裝飾器,但重點是:它不會改變接口。事實上,幾乎所有的設計模式都歸結於這一點 - 在不改變接口的情況下爲設計增加可變性。

1

添加狀態的一種方法是使用自引用數據結構(列表)。但是這使用訪問者模式,並且比您想要的要多得多。這個代碼是從A little Java, a few patterns

// a self referential data structure with different types of nodes 
abstract class Pie 
    { 
    abstract Object accept(PieVisitor ask); 
    } 
class Bottom extends Pie 
    { 
    Object accept(PieVisitor ask) { return ask.forBottom(this); } 
    public String toString() { return "crust"; } 
    } 
class Topping extends Pie 
    { 
    Object topping; 
    Pie rest; 
    Topping(Object topping,Pie rest) { this.topping=topping; this.rest=rest; } 
    Object accept(PieVisitor ask) { return ask.forTopping(this); } 
    public String toString() { return topping+" "+rest.toString(); } 
    } 
//a class to manage the data structure 
interface PieManager 
    { 
    int addTopping(Object t); 
    int removeTopping(Object t); 
    int substituteTopping(Object n,Object o); 
    int occursTopping(Object o); 
    } 
class APieManager implements PieManager 
    { 
    Pie p=new Bottom(); 
    // note: any object that implements a rational version of equal() will work 
    public int addTopping(Object t) 
     { 
     p=new Topping(t,p); 
     return occursTopping(t); 
     } 
    public int removeTopping(Object t) 
     { 
     p=(Pie)p.accept(new RemoveVisitor(t)); 
     return occursTopping(t); 
     } 
    public int substituteTopping(Object n,Object o) 
     { 
     p=(Pie)p.accept(new SubstituteVisitor(n,o)); 
     return occursTopping(n); 
     } 
    public int occursTopping(Object o) 
     { 
     return ((Integer)p.accept(new OccursVisitor(o))).intValue(); 
     } 
    public String toString() { return p.toString(); } 
    } 
//these are the visitors 
interface PieVisitor 
    { 
    Object forBottom(Bottom that); 
    Object forTopping(Topping that); 
    } 
class OccursVisitor implements PieVisitor 
    { 
    Object a; 
    OccursVisitor(Object a) { this.a=a; } 
    public Object forBottom(Bottom that) { return new Integer(0); } 
    public Object forTopping(Topping that) 
     { 
     if(that.topping.equals(a)) 
      return new Integer(((Integer)(that.rest.accept(this))).intValue()+1); 
      else return that.rest.accept(this); 
     } 
    } 
class SubstituteVisitor implements PieVisitor 
    { 
    Object n,o; 
    SubstituteVisitor(Object n,Object o) { this.n=n; this.o=o; } 
    public Object forBottom(Bottom that) { return that; } 
    public Object forTopping(Topping that) 
     { 
     if(o.equals(that.topping)) 
      that.topping=n; 
     that.rest.accept(this); 
     return that; 
     } 
    } 
class RemoveVisitor implements PieVisitor 
    { 
    Object o; 
    RemoveVisitor(Object o) { this.o=o; } 
    public Object forBottom(Bottom that) { return new Bottom(); } 
    public Object forTopping(Topping that) 
     { 
     if(o.equals(that.topping)) 
      return that.rest.accept(this); 
      else return new Topping(that.topping,(Pie)that.rest.accept(this)); 
     } 
    } 
public class TestVisitor 
    { 
    public static void main(String[] args) 
     { 
     // make a PieManager 
     PieManager pieManager=new APieManager(); 
     // add some toppings 
     pieManager.addTopping(new Float(1.2)); 
     pieManager.addTopping(new String("cheese")); 
     pieManager.addTopping(new String("onions")); 
     pieManager.addTopping(new String("cheese")); 
     pieManager.addTopping(new String("onions")); 
     pieManager.addTopping(new String("peperoni")); 
     System.out.println("pieManager="+pieManager); 
     // substitute anchovies for onions 
     int n=pieManager.substituteTopping(new String("anchovies"),new String("onions")); 
     System.out.println(n+" pieManager="+pieManager); 
     // remove the 1.2's 
     n=pieManager.removeTopping(new Float(1.2)); 
     System.out.println(n+" pieManager="+pieManager); 
     // how many anchovies do we have? 
     System.out.println(pieManager.occursTopping(new String("anchovies"))+" anchovies"); 
     } 
    }