• C#代码:用事件模式实现通知


        事件提供了一种标准的机制来通知监听者。.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     }
    复制代码
     
    
        至于选择哪种方式来实现,就要看具体的应用场景了;此外,大多数时候我们都会使用匿名委托来声明回调函数,或事件委托,所以会导致代码的运行时态有一些小波折,尤其在读别人的代码的时候,这样的情况很普遍,会不会有更好的办法来让这种回调和委托比较容易跟踪?这个还在思考中……
  • 相关阅读:
    收集的java面试题
    重载和重写的区别
    java中封装的概念
    java中多态的概念
    vue中的$on,$emit,$once,$off源码实现
    js bind的实现
    对象的深拷贝
    v-for的简单实现
    v-for的显示过滤/排序结果
    ES6的数组方法之Array.from
  • 原文地址:https://www.cnblogs.com/profession/p/4650718.html
Copyright © 2020-2023  润新知