我已閱讀了有關裝飾模式主題的一些教程,類似於this之一。基本的例子就像本教程中的一個蛋糕,或者像其他教程中的比薩一樣,裝飾者通常會通過值並在途中對其進行修改(因爲每個PizzaDecorator都會在價格上添加少量值,從而返回價格的披薩+所有裝飾)。現在,這當然是一個很好的例子,但我將這個問題應用於不太可食的問題上有點麻煩。
假設我有一個基類,它接受一個輸入,據此修改它的狀態。其中一些狀態修改會導致事件發生,並傳遞可能被視爲輸出的值。現在假設以下特徵我想單獨添加作爲裝飾:裝修模式中的多個裝飾器
- 一種用於輸出
- 輸入
- 另一種類型的輸入(例如史緩衝器解釋一組字符的所允許字節輸入值)
個別地,它們沒有太大的問題。該類的基本功能(即TakeInput(byte input)
和event Handler OutputAvailable
)駐留在基類和裝飾器可以繼承的接口中(我是否真的需要額外的抽象層,如給出的例子中,即裝飾器的單獨接口繼而從基礎接口繼承的類?)。現在,如果我在裝飾器中實現輸入緩存,那麼如何以這種方式添加輸入緩存,以使下一個裝飾器不會再隱藏它?如果我添加了一個列表來簡單地存儲輸入,並通過一個屬性使其可用,那麼如果我決定我也希望緩衝輸出,那麼該屬性將被隱藏。我可以保留對兩個裝飾器的引用 - 但這會相當混亂,或者我認爲,因爲我將需要相當多的裝飾器。如果我從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.