Adding State in Decorator Pattern

后端 未结 3 853
眼角桃花
眼角桃花 2021-01-22 09:07

I wonder how to add state to the chain of decorators that will be available to the consumer. Given this simplified model:

abstract class AbstractPizza 
{
    pub         


        
相关标签:
3条回答
  • 2021-01-22 09:36

    one way of adding state is by using a self referential data structure (a list). but this uses the visitor pattern and does more than you probably want. this code is rewritten from 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");
            }
        }
    
    0 讨论(0)
  • 2021-01-22 09:45

    I believe your component Pizza and your abstract decorator PizzaDecorator are supposed to share the same interface, that way each instance of the decorator is capable of the same operations as the core component Pizza.

    0 讨论(0)
  • 2021-01-22 09:55

    The decorator pattern is for adding additional behavior to the decorated class without the client needing to adjust. Thus it is not intended for adding a new interface (e.g. hotness, cheese) to the thing being decorated.

    A somewhat bad example of what it might be used for is where you want to change how size is calculated: you could create a MetricSizePizzaDecorator that converts the size to/from English/metric units. The client would not know the pizza has been decorated - it just calls getSize() and does whatever it needs to do with the result (for example, to calculate the price).

    I would probably not use the decorator in my example, but the point is: it does not alter the interface. In fact, nearly all design patterns come down to that - adding variability to a design without changing interfaces.

    0 讨论(0)
提交回复
热议问题