装饰模式中的多个装饰器

时间:2013-11-25 15:22:50

标签: c# design-patterns decorator

我已经阅读了一些关于装饰器模式主题的教程,类似于this一个。基本的例子是本教程中的蛋糕,或其他教程中的披萨,装饰者通常会传递值并在途中修改它们(因为每个PizzaDecorator都会在价格上添加一小部分,从而返回价格披萨+所有装饰者)。现在,这当然是一个很好的例子,但我在应用这个问题时遇到了一些麻烦 假设我有一个接受输入的基类,根据该基类修改其状态。其中一些状态修改会导致引发事件,该事件传递可以视为输出的值。现在假设我想单独添加以下功能作为装饰器:

  • 输出缓冲区
  • 输入历史记录
  • 另一种类型的输入(例如,将一组字符解释为允许的字节输入值)

单独来说,它们并不是一个问题。类的基本功能(即TakeInput(byte input)event Handler OutputAvailable)驻留在基类和装饰器可以继承的接口中(我真的需要额外的抽象层,如给定的示例中所示) ,即Decorator类的一个单独的接口,它继承自基接口?)。现在,如果我在装饰器中实现输入缓存,我该如何以这种方式添加它,下一个装饰器不会再次隐藏它?如果我添加一个列表来简单地存储输入并通过属性使其可用,那么如果我决定我也希望输出缓冲,则该属性将被隐藏。我可以保持对两个装饰器的引用 - 但是这会相当混乱,或者我认为,因为我将需要相当多的装饰器。如果我是从Decorator派生出来的,那么我最初希望通过应用这种模式避免的继承混乱就不会消失。我该如何解决这个问题?

根据要求,一段代码说明了我的问题。 (或者我希望,无论如何)

public interface ISampleClass
{
    event OutputHandler OutputAvailable;
    void TakeInput(byte input);
}

public class BaseSampleClass : ISampleClass
{
    public event OutputHandler OutputAvailable;

    void TakeInput(byte input)
    { // To keep things simple:
        this.OutputAvailable(input);
    }
}

public class SampleClassInputCacheDecorator : ISampleClass
{
    private ISampleClass decoratedClass;
    private List<byte> inputCache;

    public event OutputHandler OutputAvailable;

    public SampleClassInputCacheDecorator(ISampleClass decoratedClass)
    {
        this.decoratedClass = decoratedClass;
        this.decoratedClass.OutputAvailable += (output) => {
            this.OutputAvailable(output);
        };
    }

    public List<byte> InputHistory { get { return this.inputCache; } }

    public void TakeInput(byte input) 
    {
        this.decoratedClass.TakeInput(input);
    }
}

public class SampleClassCharInputAdapterDecorator : ISampleClass
{
    private ISampleClass decoratedClass;

    public SampleClassCharInputAdapterDecorator(ISampleClass decoratedClass)
    {
        this.decoratedClass = decoratedClass;
        this.decoratedClass.OutputAvailable += (output) => {
            this.OutputAvailable(output);
        };
    }

    public void TakeInput(byte input) 
    {
        this.decoratedClass.TakeInput(input);
    }

    public void TakeInput(char input)
    {
        switch (input)
        {
            case 'a':
                this.TakeInput(27);
                break;
            case 'b':
            // You get the idea...
        }
    }
}

// Now, I want to use the base class and get the benefit of both decorators:
ISampleClass smpl = new BaseSampleClass();
smpl = new SampleClassInputCacheDecorator(smpl);
smpl = new SampleClassCharInputAdapterDecorator(smpl);

// Dang, the input gets cached, but I can't access the InputHistory property.

1 个答案:

答案 0 :(得分:0)

Decorator是关于改变合同行为。装饰器添加了全新的行为,与第一个行为无关,而不是合同(接口)的一部分。

事实上SampleClassInputCacheDecorator不是装饰者 - 从ISampleClass的角度来看,它的行为完全不相关,因为它们根本不会影响TakeInputOutputAvailable 。它只取决于ISampleClass链,但不“装饰”它。 Proxy pattern似乎更合适。

相关问题