2009-07-01 31 views
5

Câu hỏi thiết kế - Xử lý sự kiện đa hìnhTrợ giúp thiết kế - Xử lý sự kiện đa hình

Tôi hiện đang cố gắng giảm số lượng Xử lý sự kiện trong dự án hiện tại của mình. Chúng tôi có nhiều hệ thống gửi dữ liệu qua USB. Tôi hiện đang có một thói quen để đọc trong các tin nhắn và phân tích các chi tiết tiêu đề ban đầu để xác định hệ thống thông điệp đến từ đâu. Các tiêu đề có một chút khác biệt, do đó EventArgs tôi tạo ra không giống nhau. Sau đó, tôi thông báo cho tất cả "người quan sát" về sự thay đổi. Vì vậy, những gì tôi có ngay bây giờ là như sau:

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; 
    } 
} 

đang 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; 
    } 

Và trong thuật toán phân tích cú pháp tôi có một cái gì đó như thế này trên cơ sở đó thông điệp đó là:

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

Điều tôi thực sự muốn làm là:

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); 
    } 
} 

Và vì lý do mơ hồ, chúng tôi không thể làm điều này. Vì vậy, câu hỏi của tôi là những gì sẽ là một cách tiếp cận tốt hơn cho vấn đề này?

+0

Dường như cú pháp C#. Nếu có, hãy cân nhắc thêm chi tiết này vào câu hỏi của bạn. Ngoài ra, tôi nghĩ bạn có thể gắn thẻ lại để có C# dưới dạng thẻ và sau đó bạn sẽ có nhiều lượt xem hơn. –

Trả lời

1

tôi có thể làm cho MyEvent1Args và MyEvent2Args thừa từ một lớp cơ sở chung và làm như sau:

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; 
     } 
    } 

Và trong thuật toán phân tích cú pháp tôi có một cái gì đó như thế này trên cơ sở đó thông điệp đó là:

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

Hãy nghỉ ngơi từ tính đa hình và xem xét sử dụng tính không xác định, đặc biệt là mẫu Event Aggregator nếu bạn chưa có; Fowler đầu tiên @http://martinfowler.com/eaaDev/EventAggregator.html và sau đó đăng bởi Jeremy Miller nếu bạn cần thêm ý tưởng.

Chúc mừng,
Berryl

1

Bạn có thể xem xét một vài lựa chọn (Tôi không chắc chắn chính xác những gì bạn muốn đạt được ở đây):

1. Tạo một hệ thống các EventArgs và làm cho các quan sát viên chịu trách nhiệm lọc những thứ mà họ quan tâm (đây là những gì bạn đề xuất trong câu trả lời của bạn). Điều này đặc biệt có ý nghĩa nếu một số nhà quan sát quan tâm đến nhiều loại thông điệp, được mô tả lý tưởng bởi loại lớp cơ sở.

2. Không sử dụng. Đại biểu mạng, chỉ cần tự mình thực hiện như vậy khi bạn đăng ký đại biểu, nó cũng có loại sự kiện như mong đợi. Điều này giả định bạn đã thực hiện công việc từ (1), nhưng bạn muốn chuyển bộ lọc cho lớp học của mình chứ không phải người quan sát

Ví dụ: (chưa được kiểm tra):

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); 
    } 
} 

Và khi thư mới đến, bạn chạy ủy nhiệm chính xác từ bộ điều khiển từ điển.

3. Triển khai các sự kiện theo cách thực hiện trong WinForms, để bạn không có sự kiện cơ bản cho sự kiện được tiếp xúc. Điều này có ý nghĩa nếu bạn mong đợi có nhiều sự kiện hơn người quan sát.

ví dụ .:

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; 
    } 
} 

Xin vui lòng cho tôi biết nếu bạn muốn tôi mở rộng trên bất kỳ câu trả lời.

0

Nếu bạn đang cố gắng giảm số lượng xử lý sự kiện để tiết kiệm RAM, hãy làm những gì mà Microsoft thực hiện (trong System.ComponentModel.Component) và sử dụng EventHandlerList để theo dõi tất cả các sự kiện của bạn. Here is an article that describes conserving memory use with an EventHandlerListhere is a similar article that's written in C#..

Các ý chính của nó là bạn có thể khai báo một EventHandlerList đơn (nhớ để xử lý nó) trong lớp học của bạn, cùng với một chìa khóa duy nhất:

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

... ghi đè thuộc tính sự kiện:

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

... và cung cấp một phương pháp RaiseEvent:

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

Tất nhiên, bạn chỉ cần tái sử dụng sam e EventHandlerList cho tất cả các sự kiện của bạn (nhưng với các khóa khác nhau).

3

Nếu bạn đang cố gắng giảm số lượng xử lý sự kiện theo thứ tự trừu tượng/đơn giản hóa mã bạn phải làm, sau đó áp dụng mẫu thiết kế Double Dispatch cho tổ chức sự kiện của bạn sẽ là hoàn hảo. Về cơ bản, bản sửa lỗi thanh lịch (nhưng có từ) để thực hiện các loại phôi an toàn (/ là ví dụ kiểm tra)

+2

Ok, do đó, loại giống như nghệ thuật này, nơi nó được thực hiện bằng cách sử dụng mô hình khách truy cập http://www.ddj.com/cpp/184403497?pgno=3, điều này có vẻ như một cách tiếp cận tuyệt vời – SwDevMan81

+0

có, mô hình khách truy cập có lẽ là lớn nhất người sử dụng công văn kép. Đó là một chút dễ dàng hơn trong C#. Bài viết này bắt đầu với phiên bản truyền thống (biên dịch, không phản ánh) và kết thúc bằng một phiên bản phản chiếu: http://accu.org/index.php/journals/1376 và đây là một phiên bản khác sử dụng sự phản chiếu: http:/www.stackoverflow.com/questions/42587/ –

+0

Tôi đã thực hiện điều này và đăng nó dưới câu hỏi [Mẫu thiết kế để xử lý nhiều loại tin nhắn] (http://stackoverflow.com/a/16407143/95573) làm câu trả lời, thx cho đề xuất @Rob Fonseca-Ensor – SwDevMan81

Các vấn đề liên quan