2010-04-06 16 views
1

我已經定義的事件類的類:添加行爲一組

Event 

和下面所有的類都是從事件繼承:

SportEventType1 SportEventType2 SportEventType3 SportEventType4 

現在我只會有SportEvents但我不我不知道未來是否會有其他一些與體育無關的事件。後來,我將要繪製一些圖形,其中包含來自事件的信息,而繪圖邏輯可能有點複雜。但是,目前,我認爲我不應該考慮如何完成繪圖,我相信如果繪圖部分不是Event/SportEventX類鏈的一個組成部分,也許會更好。

我在找這個問題的解決方案。我知道我可以讓Event有一個實例變量(屬性,對於java羣體)指向某個IDrawInterface,但這會使事件類「假設」它將在稍後用於繪製。如果可能的話,我想讓事件類忘記這一點。

謝謝!

回答

3

您有意將繪圖過程的知識保存在Event類層次結構之外。

以OO語言處理這類事情的常見方法是Visitor Pattern

如果您實際上無法更改Event類以添加訪客所需的accept(Visitor v),則可以考慮使用DecoratorAdapter。儘管接受方法根據子類而變化可能會很痛苦。我會更多地考慮這個問題,也許今晚會再補充一點。現在,我必須開始工作。

+0

從我現在讀的訪客模式,這意味着我必須添加一個方法到我的事件類。如果這個班不是我的/我不能再改變它了? – 2010-04-06 12:33:15

+0

在C#中,可以使用擴展方法將東西添加到不屬於你的類中。 – GWLlosa 2010-04-06 13:50:03

+0

雖然擴展方法不會給你動態分派,所以你不能使用它們實現訪問者模式。 – munificent 2010-04-06 17:33:00

1

另一個解決方案可能是在不同的sportingevents可以繼承的DrawbleEvent抽象類。

public abstract DrawableEvent 
{ 
    Event event; 
    IDrawingStrategy drawingstrategy; 
    public Draw() 
    { 
     drawingStrategy.Draw(); 
    } 

} 
public SportingEvent1 : DrawableEvent 
{ 
    SprortingEvent1(Event event, IdrawingStrategy strategy) 
    { 
     this.event=event; 
     this.drawingstrategy = strategy; 
    } 
} 

事件引用可以根據需要的位置進入策略或彈出事件。

+0

從我可以看到,這將需要每個SportEvent我會有一個SportingEvent(即可繪製),對不對?儘管如此,在更糟的情況下,我會使用它。謝謝 – 2010-04-06 20:39:48

+0

是的,每個SportingEvent都從DrawableEvent繼承。 DrawingStrategy有點可選。如果繪畫行爲對於某些sportingEvent是相同的,則更有意義。 – derdo 2010-04-07 16:48:19

1

這是一個更復雜但非常靈活的方法。我們將定義一個接口 的類型,可以得出一些事件:

interface IEventRenderer 
{ 
    // Draw the given event, if it can. Return true if the event was drawn, 
    // false otherwise. 
    bool Draw(Event event); 
} 

它做兩件事情:它檢查,看它是否可以得出一個給定的事件,並且,如果是這樣, 吸引它。否則它會保留並返回false。

例如,可以使Sport1Events一類的樣子:

class Sport1EventRenderer : IEventRenderer 
{ 
    public bool Draw(Event event) 
    { 
     var sportEvent = event as Sport1Event; 

     // can only draw this type 
     if (sportEvent == null) return false; 

     // draw the event... 

     return true; 
    } 
} 

然後,我們將定義一個註冊表類。它的任務是保持 這些渲染器上收集和掛斷繪製事件到合適的 一個工作:

class EventRendererRegistry 
{ 
    public void Add(IEventRenderer renderer) 
    { 
     mRenderers.Add(renderer); 
    } 

    public void Draw(Event event) 
    { 
     foreach (var renderer in mRenderers) 
     { 
      if (renderer.Draw(event)) break; 
     } 
    } 

    private readonly List<IEventRenderer> mRenderers = new List<IEventRenderer>(); 
} 

它所做的就是尋找能夠成功地繪製該事件的第一渲染器。 你會再使用此類似:

var registry = new EventRendererRegistry(); 
registry.Add(new Sport1EventRenderer()); 

registry.Draw(someEvent); 

優點:

  • 事件類型並連接到任何渲染代碼。
  • 渲染器不相互耦合。
  • 渲染器僅與他們關心的事件相關聯。 (例如,一個 Sport2EventRenderer將不需要耦合到Sport1Event。)
  • 渲染可以執行任意邏輯來確定它們是否合適。我們只是在這裏做了一個類型測試 ,但是我們可以看到這個事件是否實現了某個接口,具有某種屬性,處於某種狀態,等等。
  • 相對較快。沒有超越簡單鑄造的思考。

缺點:

  • 相當複雜。
  • 運行時可能會失敗以查找匹配的渲染器。
  • 每次都必須遍歷渲染器集合才能找到匹配項。
+0

關於「每次都必須遍歷渲染器集合以查找匹配項」。你可以使用一個Hashtable,這可以大大提高性能。 – 2010-04-06 21:30:17

+0

鑰匙是什麼?就目前而言,您可以通過任意謂詞函數來選擇渲染器。如果你願意,你可以在一天中的某個時間選擇一個渲染器。使用散列表代替它可能會更快(取決於您的密鑰以及它的生成方式),但也會失去一些動態性。 – munificent 2010-04-08 15:07:55

+0

我想說,類的類型可能是關鍵。或不? – 2010-04-09 12:25:37