zoukankan      html  css  js  c++  java
  • 【原】从头学习设计模式(六)——观察者模式

    一、引入

      在系统设计中,我们常常需要设计一种消息通知的模块,从服务器端将消息分发给客户端。这样的功能实现可以有很多不同的方式,今天我们来主要介绍一下设计模式中针对这种情况的一种处理方法,也就是观察者模式。观察者模式又常被叫作发布-订阅模式,如果你曾经向移动公司订过手机报,那就很容易理解了,就是把你的手机号注册到移动的手机报发送大名单里,系统就会定时给你发消息了。观察者模式的实现有很多种不同形式,比较直观的就是今天我们本篇要介绍的 “注册——通知”形式。首先按老规矩,我们先来看一下标准定义。

      观察者模式(Observer):定义了一种一对多的依赖关系,让多个观察者同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们可以自动更新自己。

      这里有几个关键点:

      1.这是一种一对多的关系

      2.多个观察者去监听一个对象,观察者是主动的参与的,被监听对象应该不关心有多少个观察者在监听他。

      3.被监听对象只管发通知,观察者自己去处理收到通知后的处理动作。

      4.观察者可以主动注册或者撤销注册,这样就将观察者和监听对象隔离开来。

    二、类图

     

    从以上类图中我们来总结观察者模式中的几个重要要素:

    1.抽象主题:抽象的被观察角色,定义了可以增加或删除观察者的方法。一般用一个抽象类或接口实现。(不是必须的)

    2.抽象观察者:抽象的观察者,包含一个Update()方法,在得到通知时更新自己。

    3.具体主题对象:在具体的主题内部发生变化时,向观察者发出通知。

    4.具体观察者对象:在收到主题通知时更新自己状态。

    三、示例代码

     我们来用一个比较简单的"Server——Client"消息推送的例子来认识一下观察者模式的使用过程。

     1.首先需要定义一个抽象的客户端接口,服务器只需要和接口打交道。这样遵守了“面向接口编程,而非面向实现编程”的OO原则

    1     /// <summary>
    2     /// 客户端抽象接口
    3     /// </summary>
    4     public interface IClient
    5     {
    6         void Notification(string message);
    7     }

     2.具体的客户端实现,每个客户端必须实现用于接收通知并显示通知的 Notification()方法

     1     /// <summary>
     2     /// 客户端A
     3     /// </summary>
     4     public class ClientA : IClient
     5     {
     6         //用于显示接收到消息的方法
     7         public void Notification(string message)
     8         {
     9            Console.WriteLine(string.Format("This is Client A. 
     New Message Received:{0} ",message));
    10         }
    11     }
    12     /// <summary>
    13     /// 客户端B
    14     /// </summary>
    15     public class ClientB:IClient
    16     {
    17         public void Notification(string message)
    18         {
    19             Console.WriteLine(string.Format("This is Client B. 
     New Message Received:{0}", message));
    20         }
    21     }
    22     /// <summary>
    23     /// 客户端C
    24     /// </summary>
    25     public class ClientC:IClient
    26     {
    27         public void Notification(string message)
    28         {
    29             Console.WriteLine(string.Format("This is Client C. 
     New Message Received:{0}", message));
    30         }
    31     }

     3.服务端的实现,运用了委托和事件来处理与客户端的消息发送

     1     /// <summary>
     2     /// 服务器
     3     /// </summary>
     4     public class Server
     5     {
     6         //负责发送消息的委托和事件
     7         //客户端只要将接收消息的方法绑定在这个事件上就可以得到新消息
     8         public delegate void SendMessageHandler(string msg);
     9 
    10         public static event SendMessageHandler SendMessageEvent;
    11 
    12         //执行消息发送的方法
    13         public static void Notify()
    14         {
    15             if(SendMessageEvent!=null)
    16             {
    17                 SendMessageEvent(Message);
    18             }
    19         }
    20 
    21         public static string Message;
    22     }

     4. 调用示例,服务器向所有客户端发送消息通知。

     1         static void Main(string[] args)
     2         {
     3             //将需要发送通知的客户端集中放到一个列表中管理
     4             IList<IClient> ClientList=new List<IClient>();
     5             ClientList.Add(new ClientA());
     6             ClientList.Add(new ClientB());
     7             ClientList.Add(new ClientC());
     8             //将所有客户端的接收消息方法注册到服务器的发送事件上
     9             foreach (var client in ClientList)
    10             {
    11                 Server.SendMessageEvent += client.Notification;
    12             }
    13             //定义服务器要发送的消息内容
    14             Server.Message = "You got a message from Server!";
    15             //开始执行发送
    16             Server.Notify();
    17             Console.ReadKey();
    18 
    19         }

     5.运行结果

    同样,客户端也可以撤销消息的通知事件,我们把调用方法稍作修改,如下

     1         static void Main(string[] args)
     2         {
     3             //创建三个客户端对象
     4             ClientA clientA=new ClientA();
     5             ClientB clientB=new ClientB();
     6             ClientC clientC=new ClientC();
     7             
     8             //分别为每个客户端注册消息事件
     9             Server.SendMessageEvent += clientA.Notification;
    10             Server.SendMessageEvent += clientB.Notification;
    11             Server.SendMessageEvent += clientC.Notification;
    12 
    13             Server.Message = "You got a message from Server!";
    14             Server.Notify();
    15 
    16             //客户端C取消接收消息通知
    17             Console.WriteLine("---------------------- Client C Ignore The Message ---------------------------");
    18             Server.SendMessageEvent -= clientC.Notification;
    19 
    20             Server.Message = "Client C has gone.";
    21             Server.Notify();
    22 
    23             Console.ReadKey();
    24 
    25         }

    运行结果:

    取消注册后,Client C 就再也收不到消息通知了。

    四、总结

    观察者模式实现了抽象与具体的分离,定义了稳定的更新消息传递机制,使类之间各自维护自己的功能,提高系统的可重用性和可维护性。

    优点:

    1.观察者与被观察者之间建立一个抽象的耦合关系,被观察者(主题角色)并不知道和关心每个一具体的观察者,它只要关心一个共同的观察者接口。

    2.观察者模式支持广播通信。

    缺点:

    如果有很多观察者同时监听一个主题角色对象,主题角色要花费很多时间去通知每个观察者。可以考虑用多线程的方式去投递通知。

  • 相关阅读:
    MongoDB配置及解答mongodb cmd中安装及连接数据库 mongodb无法安装及连接数据库解答
    类封装版学生管理系统,连接数据库,增删改查,拿去用,不谢。
    python学生管理系统连接数据库版,很详细,这个是用函数版的增删改查,拿去用,不谢。
    京东双十一
    Ubuntu中以root权限运行软件sudo命令不输入密码
    Ubuntu 18.04中sudo运行的程序无法切换输入法中文输入问题
    UVA12558 埃及分数
    NOI1999 生日蛋糕
    Tarjan
    AC自动机
  • 原文地址:https://www.cnblogs.com/ytaozhao/p/3406408.html
Copyright © 2011-2022 走看看