2009-07-01 97 views
5

設計問題 - 多態事件處理設計幫助 - 多態事件處理

我正在嘗試減少當前項目中事件處理的數量。我們有多個通過USB發送數據的系統。我現在有一個例程來讀取消息並解析初始頭部細節以確定消息來自哪個系統。標題有點不同,所以我創建的EventArgs不一樣。然後我通知所有「觀察員」這一變化。所以我現在所擁有的是以下幾點:

public enum Sub1Enums : byte 
{ 
    ID1 = 0x01, 
    ID2 = 0x02 
} 

public enum Sub2Enums : ushort 
{ 
    ID1 = 0xFFFE, 
    ID2 = 0xFFFF 
} 

public class MyEvent1Args 
{ 
    public Sub1Enums MessageID; 
    public byte[] Data; 
    public MyEvent1Args(Sub1Enums sub1Enum, byte[] data) 
    { 
     MessageID = sub1Enum; 
     Data = data; 
    } 
} 

public class MyEvent2Args 
{ 
    public Sub2Enums MessageID; 
    public byte[] Data; 
    public MyEvent2Args(Sub2Enums sub2Enum, byte[] data) 
    { 
     MessageID = sub2Enum; 
     Data = data; 
    } 
} 

Form1的代碼

public class Form1 
{ 
    public delegate void TestHandlerCurrentlyDoing(MyEvent1Args eventArgs1); 
    public delegate void TestHandlerCurrentlyDoingAlso(MyEvent2Args eventArgs2); 

    public event TestHandlerCurrentlyDoing mEventArgs1; 
    public event TestHandlerCurrentlyDoingAlso mEventArgs2; 

    public Form1() 
    { 
     mEventArgs1 += new TestHandlerCurrentlyDoing(Form1_mEventArgs1); 
     mEventArgs2 += new TestHandlerCurrentlyDoingAlso(Form1_mEventArgs2); 
    } 

    void Form1_mEventArgs2(MyEvent2Args eventArgs2) 
    { 
     // Do stuff here 
     Sub2Enums mid = my_event2_args.MessageID; 
     byte[] data = my_event2_args.Data; 
    } 

    void Form1_mEventArgs1(MyEvent1Args eventArgs1) 
    { 
     // Do stuff here 
     Sub1Enums mid = my_event1_args.MessageID; 
     byte[] data = my_event1_args.Data; 
    } 

而在解析算法我有這樣的事情基於它是一種信息:

void ParseStuff() 
{ 
    if (mEventArgs1 != null) 
    { 
     mEventArgs1(new MyEvent1Args(Sub1Enums.ID1, new byte[] { 0x01 })); 
    } 
    if (mEventArgs2 != null) 
    { 
     mEventArgs2(new MyEvent2Args(Sub2Enums.ID2, new byte[] { 0x02 })); 
    } 
} 

我真正想要做的是:

public class Form1 
{ 
    public delegate void TestHandlerDesired(MyEvent1Args eventArgs1); 
    public delegate void TestHandlerDesired(MyEvent2Args eventArgs2); 

    public event TestHandlerDesired mEventArgs; 

    public Form1() 
    { 
     mEventArgs += new TestHandlerDesired (Form1_mEventArgs1); 
     mEventArgs += new TestHandlerDesired (Form1_mEventArgs2); 
    } 
} 

由於含糊不清的原因,我們不能這樣做。所以我的問題是什麼會更好地解決這個問題?

+0

它看起來像C#語法。如果是這樣,請考慮在您的問題中添加這些細節。另外,我認爲您可以重新將C#作爲標籤,然後您可以看到更多的視圖。 – 2009-07-26 14:20:55

回答

1

我可以做MyEvent1Args和MyEvent2Args從一個公共基類派生並執行以下操作:

public class BaseEventArgs : EventArgs 
{ 
    public byte[] Data; 
} 

public class MyEvent1Args : BaseEventArgs 
{ … } 
public class MyEvent2Args : BaseEventArgs 
{ … } 


public delegate void TestHandlerWithInheritance(BaseEventArgs baseEventArgs); 

public event TestHandlerWithInheritance mTestHandler; 

mTestHandler += new TestHandlerWithInheritance(TestHandlerForEvent1Args); 
mTestHandler += new TestHandlerWithInheritance(TestHandlerForEvent2Args); 

    void TestHandlerForEvent1Args(BaseEventArgs baseEventArgs) 
    { 
     MyEvent1Args my_event1_args = (baseEventArgs as MyEvent1Args); 
     if (my_event1_args != null) 
     { 
      // Do stuff here 
      Sub1Enums mid = my_event1_args.MessageID; 
      byte[] data = my_event1_args.Data; 
     } 
    } 

    void TestHandlerForEvent2Args(BaseEventArgs baseEventArgs) 
    { 
     MyEvent2Args my_event2_args = (baseEventArgs as MyEvent2Args); 
     if (my_event2_args != null) 
     { 
      // Do stuff here 
      Sub2Enums mid = my_event2_args.MessageID; 
      byte[] data = my_event2_args.Data; 
     } 
    } 

而在解析算法我有這樣的事情基於它是一種信息:

 if (mTestHandler!= null) 
     { 
      mTestHandler (new MyEvent1Args(Sub1Enums.ID1, new byte[] { 0x01 })); 
     } 
     if (mTestHandler!= null) 
     { 
      mTestHandler (new MyEvent2Args(Sub2Enums.ID2, new byte[] { 0x02 })); 
     } 
1

你可以考慮幾個選擇(我不知道你想在這裏實現什麼):

1.創建的EventArgs的層次結構,使觀察者負責過濾他們感興趣的東西(這是你在答案中提出的)。如果一些觀察者對多種類型的消息感興趣,理想情況下用基類類型描述,這尤其有意義。

2.不要使用.Net委託,只需自己實現它,這樣當您註冊委託時,它也會採用它期望的事件類型。這假設你已經完成了(1)的工作,但是你希望將過濾傳遞給你的班級而不是觀察員。

例如, (未經測試):

enum MessageType 
{ 
Type1,Type2 
} 
private Dictionary<MessageType, TestHandlerWithInheritance> handlers; 
public void RegisterObserver(MessageType type, TestHandlerWithInheritance handler) 
{ 
    if(!handlers.ContainsKey(type)) 
    { 
    handlers[key] = handler; 
    } 
    else 
    { 
    handlers[key] = Delegate.Combine(handlers[key] , handler); 
    } 
} 

當新郵件到達,您從處理器字典正確的委託。

的方式實現其事件中的WinForms完成的,所以你不必永遠暴露事件的潛在事件。如果你期望比觀察者有更多的事件,這是有道理的。

例如爲:

public event EventHandler SthEvent 
{ 
    add 
    { 
     base.Events.AddHandler(EVENT_STH, value); 
    } 
    remove 
    { 
     base.Events.RemoveHandler(EVENT_STH, value); 
    } 
} 

public void AddHandler(object key, Delegate value) 
{ 
    ListEntry entry = this.Find(key); 
    if (entry != null) 
    { 
     entry.handler = Delegate.Combine(entry.handler, value); 
    } 
    else 
    { 
     this.head = new ListEntry(key, value, this.head); 
    } 
} 


public void RemoveHandler(object key, Delegate value) 
{ 
    ListEntry entry = this.Find(key); 
    if (entry != null) 
    { 
     entry.handler = Delegate.Remove(entry.handler, value); 
    } 
} 


private ListEntry Find(object key) 
{ 
    ListEntry head = this.head; 
    while (head != null) 
    { 
     if (head.key == key) 
     { 
      return head; 
     } 
     head = head.next; 
    } 
    return head; 
} 

private sealed class ListEntry 
{ 
    // Fields 
    internal Delegate handler; 
    internal object key; 
    internal EventHandlerList.ListEntry next; 

    // Methods 
    public ListEntry(object key, Delegate handler, EventHandlerList.ListEntry next) 
    { 
     this.next = next; 
     this.key = key; 
     this.handler = handler; 
    } 
} 

請讓我知道如果你要我任何答案的擴大。

0

如果您嘗試減少事件句柄的數量以節省RAM,請執行microsoft(在System.ComponentModel.Component中)並使用EventHandlerList來跟蹤所有事件。 Here is an article that describes conserving memory use with an EventHandlerListhere is a similar article that's written in C#.

它的要點是,你可以聲明一個EventHandlerList(記得要處理它)在你的類,它有一個獨特的密鑰一起:

public class Foo 
{ 
    protected EventHandlerList listEventDelegates = new EventHandlerList(); 
    static readonly object mouseDownEventKey = new object(); 

...重寫事件屬性:

public event MouseEventHandler MouseDown { 
    add { listEventDelegates.AddHandler(mouseDownEventKey, value); } 
    remove { listEventDelegates.RemoveHandler(mouseDownEventKey, value); } 
} 

...並提供的RaiseEvent方法:

protected void RaiseMouseDownEvent(MouseEventArgs e) 
{ 
    MouseEventHandler handler = (MouseEventHandler) base.Events[mouseDownEventKey]; 
    if (handler != null) 
    { 
     handler(this, e); 
    } 
} 

當然,你只是重複使用SAM e EventHandlerList用於所有事件(但使用不同的密鑰)。

3

如果您嘗試減少事件句柄的數量以便抽象/簡化您必須執行的編碼,那麼將Double Dispatch設計模式應用於事件參數將是完美的。它基本上是一個優雅(但羅嗦)的修復程序,用於執行安全類型轉換(/是instanceof檢查)

+2

好吧,有點像這個artical,其實施使用訪問者模式http://www.ddj.com/cpp/184403497?pgno=3,這似乎是一個偉大的方法 – SwDevMan81 2009-07-29 15:09:31