Добавление состояния в шаблон декоратора - PullRequest
2 голосов
/ 09 ноября 2011

Интересно, как добавить состояние в цепочку декораторов, которая будет доступна потребителю. Учитывая эту упрощенную модель:

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.

Какую часть я пропускаю? Неправильный рисунок?

Спасибо за помощь! Приветствия

Ответы [ 3 ]

3 голосов
/ 09 ноября 2011

Шаблон декоратора предназначен для добавления дополнительного поведения к оформленному классу без необходимости настройки клиента.Таким образом, он не предназначен для добавления нового интерфейса (например, hotness, cheese) к декорируемой вещи.

Несколько плохой пример того, для чего он может быть использован, где вы хотите изменитьsize рассчитывается: вы можете создать MetricSizePizzaDecorator, который преобразует размер в / из английских / метрических единиц.Клиент не знал бы, что пицца была украшена - он просто вызывает getSize() и делает все, что нужно с результатом (например, для расчета цены).

Я бы, вероятно, не использовал декораторв моем примере, но дело в том, что это не меняет интерфейс.Фактически, почти все шаблоны проектирования сводятся к этому - добавление изменчивости в дизайн без изменения интерфейсов.

1 голос
/ 09 ноября 2011

один из способов добавления состояния - использование само-ссылочной структуры данных (список).но это использует шаблон посетителя и делает больше, чем вы, вероятно, хотите.этот код переписан с немного Java, несколько шаблонов

// 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 голос
/ 09 ноября 2011

Я полагаю, что ваш компонент Pizza и ваш абстрактный декоратор PizzaDecorator должны совместно использовать один и тот же интерфейс, поэтому каждый экземпляр декоратора может выполнять те же операции, что и основной компонент Pizza.

...