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
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");
}
}