這是一個更復雜但非常靈活的方法。我們將定義一個接口 的類型,可以得出一些事件:
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。)
- 渲染可以執行任意邏輯來確定它們是否合適。我們只是在這裏做了一個類型測試 ,但是我們可以看到這個事件是否實現了某個接口,具有某種屬性,處於某種狀態,等等。
- 相對較快。沒有超越簡單鑄造的思考。
缺點:
- 相當複雜。
- 運行時可能會失敗以查找匹配的渲染器。
- 每次都必須遍歷渲染器集合才能找到匹配項。
從我現在讀的訪客模式,這意味着我必須添加一個方法到我的事件類。如果這個班不是我的/我不能再改變它了? – 2010-04-06 12:33:15
在C#中,可以使用擴展方法將東西添加到不屬於你的類中。 – GWLlosa 2010-04-06 13:50:03
雖然擴展方法不會給你動態分派,所以你不能使用它們實現訪問者模式。 – munificent 2010-04-06 17:33:00