改进C#代码之25:用事件模式实现通知


  事件提供了一种标准的机制来通知监听者。.NET的事件模式使用了事件语法来实现观察者模式。任意数量的客户对象都可以将自己的处理函数注册到事件上,然后处理这些事件。这些客户对象不需要再编译期就给出。时间也不必非要有订阅者才能正常工作。在C#中使用事件可以降低发送者和可能的通知接受者之间的耦合。发送者可以完全独立于接收者进行开发。事件是实现广播类型行为信息的标准方式。 

 

    下面按照使用场景的不同,简单列举三种事件模式的实现方式:

 

    0. 公共代码部分

 

  1     /// <summary>

 2       ///  日志参数类
 3       ///   </summary>
 4       public   class  LoggerEventArgs : EventArgs
 5      {
 6           public   string  Message {  get private   set ; }
 7           public   int  Priority {  get private   set ; }
 8 
 9           public  LoggerEventArgs( int  p,  string  m)
10          {
11              Priority  =  p;
12              Message  =  m;
13          }
14      }

 

    1. 最常用方式

 

  1     /// <summary>

 2       ///  日志类(第一版):最常见的使用方法,适用于单一调用者情况。
 3       ///   </summary>
 4       public   class  Logger
 5      {
 6           ///   <summary>
 7           ///  内部事件句柄
 8           ///   </summary>
 9           public   event  EventHandler < LoggerEventArgs >  Log;
10           ///   <summary>
11           ///  内部日志单键实例
12           ///   </summary>
13           private   static  Logger theOnly  =   null ;
14           public   static  Logger Singleton
15          {
16               get  {  return  theOnly; }
17          }
18 
19           private  Logger()
20          { }
21 
22           static  Logger()
23          {
24              theOnly  =   new  Logger();
25          }
26 
27           ///   <summary>
28           ///  添加日志信息
29           ///   </summary>
30           ///   <param name="priority"></param>
31           ///   <param name="msg"></param>
32           public   void  AddMsg( int  priority,  string  msg)
33          {
34               //  该临时变量可预防多线程环境中的竞争条件
35              EventHandler < LoggerEventArgs >  l  =  Log;
36               //  执行事件方法
37               if  (l  !=   null )
38              {
39                  l( this new  LoggerEventArgs(priority, msg));
40              }
41          }
42      }

 

    2. 针对事件数量多的情况

 

  1     /// <summary>

 2       ///  日志类(第二版):适用于包含事件数量非常多的情况,即添加了一个事件容器,避免因多事件导致的设计臃肿。
 3       ///   </summary>
 4       public   sealed   class  Logger
 5      {
 6           ///   <summary>
 7           ///  事件容器
 8           ///   </summary>
 9           private   static  System.ComponentModel.EventHandlerList Handlers  =   new  System.ComponentModel.EventHandlerList();
10 
11           ///   <summary>
12           ///  添加事件
13           ///   </summary>
14           ///   <param name="system"></param>
15           ///   <param name="ev"></param>
16           public   static   void  AddLogger( string  system, EventHandler < LoggerEventArgs >  ev)
17          {
18              Handlers.AddHandler(system, ev);
19          }
20 
21           ///   <summary>
22           ///  清除事件
23           ///   </summary>
24           ///   <param name="system"></param>
25           ///   <param name="ev"></param>
26           public   static   void  RemoveLogger( string  system, EventHandler < LoggerEventArgs >  ev)
27          {
28              Handlers.RemoveHandler(system, ev);
29          }
30 
31           ///   <summary>
32           ///  添加日志信息
33           ///   </summary>
34           ///   <param name="system"></param>
35           ///   <param name="priority"></param>
36           ///   <param name="msg"></param>
37           public   static   void  AddMsg( string  system,  int  priority,  string  msg)
38          {
39               if  ( ! string .IsNullOrEmpty(system))
40              {
41                   //  根据key获取相应的事件
42                  EventHandler < LoggerEventArgs >  l  =  Handlers[system]  as  EventHandler < LoggerEventArgs > ;
43                   //  事件参数
44                  LoggerEventArgs args  =   new  LoggerEventArgs(priority, msg);
45                   if  (l  !=   null )
46                  {
47                      l( null , args);
48                  }
49                   //  若不存在,执行默认事件
50                  l  =  Handlers[ "" as  EventHandler < LoggerEventArgs > ;
51                   if  (l  !=   null )
52                  {
53                      l( null , args);
54                  }
55              }
56          }
57      }

 

    3. 针对事件数量多的情况(泛型版本) 

 

  1     /// <summary>

 2       ///  日志类(第三版):适用于多事件情况的泛型版本。主要优势是降低了转型/转换的工作,但增加了一些用来映射事件的代码。
 3       ///   </summary>
 4       public   sealed   class  Logger
 5      {
 6           ///   <summary>
 7           ///  事件字典
 8           ///   </summary>
 9           private   static  Dictionary < string , EventHandler < LoggerEventArgs >>  Handlers  =   new  Dictionary < string , EventHandler < LoggerEventArgs >> ();
10 
11           ///   <summary>
12           ///  添加事件
13           ///   </summary>
14           ///   <param name="system"></param>
15           ///   <param name="ev"></param>
16           static   public   void  AddLogger( string  system, EventHandler < LoggerEventArgs >  ev)
17          {
18               if  (Handlers.ContainsKey(system))
19              {
20                  Handlers[system]  +=  ev;
21              }
22               else
23              {
24                  Handlers.Add(system, ev);
25              }
26          }
27 
28           ///   <summary>
29           ///  清除事件
30           ///   </summary>
31           ///   <param name="system"></param>
32           ///   <param name="ev"></param>
33           static   public   void  RemoveLogger( string  system, EventHandler < LoggerEventArgs >  ev)
34          {
35              Handlers[system]  -=  ev;
36          }
37 
38           ///   <summary>
39           ///  添加日志信息
40           ///   </summary>
41           ///   <param name="system"></param>
42           ///   <param name="priority"></param>
43           ///   <param name="msg"></param>
44           static   public   void  AddMsg( string  system,  int  priority,  string  msg)
45          {
46               if  ( string .IsNullOrEmpty(system))
47              {
48                   //  从字典中获取事件
49                  EventHandler < LoggerEventArgs >  l  =   null ;
50                  Handlers.TryGetValue(system,  out  l);
51                   //  事件参数
52                  LoggerEventArgs args  =   new  LoggerEventArgs(priority, msg);
53                   //  执行事件
54                   if  (l  !=   null )
55                  {
56                      l( null , args);
57                  }
58                   //  若不存在,则尝试执行默认事件
59                  l  =  Handlers[ "" as  EventHandler < LoggerEventArgs > ;
60                   if  (l  !=   null )
61                  {
62                      l( null , args);
63                  }
64              }
65          }
66      }

 

    至于选择哪种方式来实现,就要看具体的应用场景了;此外,大多数时候我们都会使用匿名委托来声明回调函数,或事件委托,所以会导致代码的运行时态有一些小波折,尤其在读别人的代码的时候,这样的情况很普遍,会不会有更好的办法来让这种回调和委托比较容易跟踪?这个还在思考中……

 

    希望能有所帮助~

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值