Adding State to the Decorator Pattern

I wonder how to add state to the decorator chain, which will be available to the consumer. Given this simplified model:

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

Now, if all of them implement the printing method and distribute it, although the chain, all this is good. But how does it work for the state? I cannot access the size property on HotBigCheesyPizza.

Which part am I missing? Invalid template?

Thanks for the help! Greetings

+2
source share
3 answers

The decorator template is designed to add additional behavior to the decorated class without the need to configure the client. Thus, it is not intended to add a new interface (for example, hotness , cheese ) to the decorated item.

A somewhat bad example of what it can be used for is where you want to change the way you calculate size : you can create a MetricSizePizzaDecorator that converts the size to / from English / metric units. The client did not know that the pizza was decorated - it simply calls getSize() and does everything that is needed for the result (for example, to calculate the price).

I would probably not use a decorator in my example, but the fact is that it does not change the interface. In fact, almost all design patterns boil down to this β€” adding variability to the design without changing the interfaces.

+3
source

I believe that your Pizza component and your abstract PizzaDecorator decorator should have the same interface, so each instance of the decorator can perform the same operations as the main Pizza component.

+1
source

One way to add state is to use your own reference data structure (list). but it uses a visitor pattern and does more than you probably want. this code is rewritten from Little Java, several templates

 // 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"); } } 
+1
source

Source: https://habr.com/ru/post/1386006/


All Articles