2013-11-25 27 views
1

我已閱讀了有關裝飾模式主題的一些教程,類似於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. 

回答

0

裝飾即將改變承包行爲。你裝飾者增加了全新的行爲,與第一個行爲無關,而不是合同的一部分(界面)。

其實SampleClassInputCacheDecorator不是裝飾 - 它的行動是從ISampleClass的觀點完全不相干的,因爲它們不影響TakeInputOutputAvailable可言。它只取決於ISampleClass鏈,但不「裝飾」它。 Proxy pattern在這裏似乎更合適。