【问题标题】:Adding State in Decorator Pattern在装饰器模式中添加状态
【发布时间】:2011-12-24 21:28:51
【问题描述】:

我想知道如何将状态添加到可供消费者使用的装饰器链中。鉴于此简化模型:

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 !
}

现在,如果他们都实现了 print 方法并通过链传播它,那就很好了。但这对国家有什么作用?我无法访问 HotBigCheesyPizza 上的 size 属性。

我缺少什么?错误的模式?

感谢您的帮助! 干杯

【问题讨论】:

  • 如果您的 HotPizzaDecorator 不接受 CheesyPizzaDecorator,您将如何构建 HotBigCheesyPizza...您能举个例子吗?

标签: oop design-patterns implementation decorator state


【解决方案1】:

装饰器模式用于向装饰类添加额外的行为,而无需客户端进行调整。因此,它不适用于向被装饰的事物添加新接口(例如hotness、cheese)。

它可能用于的一个有点糟糕的例子是你想改变size 的计算方式:你可以创建一个MetricSizePizzaDecorator 来将大小转换为英制/公制单位。客户不会知道披萨已经被装饰——它只是调用getSize() 并对结果做任何它需要做的事情(例如,计算价格)。

我可能不会在我的示例中使用装饰器,但重点是:它不会改变界面。事实上,几乎所有的设计模式都归结为这一点——在不改变界面的情况下为设计增加可变性。

【讨论】:

    【解决方案2】:

    添加状态的一种方法是使用自引用数据结构(列表)。但这使用了访问者模式,并且比您可能想要的更多。这段代码是从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");
            }
        }
    

    【讨论】:

      【解决方案3】:

      我相信您的组件Pizza 和您的抽象装饰器PizzaDecorator 应该共享相同的接口,这样装饰器的每个实例都能够与核心组件Pizza 执行相同的操作。

      【讨论】:

      • 这意味着所有装饰器都实现相同的属性。我正在尝试添加状态。 HotPizzaDecorator 不应该知道大小,而 CheesyPizza 不知道辣度。
      猜你喜欢
      • 1970-01-01
      • 2021-11-24
      • 1970-01-01
      • 2013-04-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多