zoukankan      html  css  js  c++  java
  • c#设计模式之观察者模式(Observer Pattern)

    场景出发

    一个月高风黑的晚上,突然传来了尖锐的猫叫,宁静被彻底打破,狗开始吠了,大人醒了,婴儿哭了,小偷跑了

    这个过程,如果用面向对象语言来描述,简单莫过于下:

     1    public class Cat
     2     {
     3         public void Miao()
     4         {
     5             Console.WriteLine("猫叫了..........");
     6 
     7             new Dog().Wang();
     8             new Parents().Wake();
     9             new Baby().Cry();
    10             new Thief().Run();
    11         }
    12     }
    13     public class Dog
    14     {
    15         public void Wang()
    16         {
    17             Console.WriteLine("狗汪了..........");
    18         }
    19     }
    20 
    21     public class Parents
    22     {
    23         public void Wake()
    24         {
    25             Console.WriteLine("大人醒了..........");
    26         }
    27     }
    28 
    29     public class Baby
    30     {
    31         public void Cry()
    32         {
    33             Console.WriteLine("婴儿哭了..........");
    34         }
    35     }
    36 
    37     public class Thief
    38     {
    39         public void Run()
    40         {
    41             Console.WriteLine("小偷跑了..........");
    42         }
    43     }
    Object
    1     class Program
    2     {
    3         static void Main(string[] args)
    4         {
    5             Cat cat = new Cat();
    6             cat.Miao();
    7         }
    8     }
    Main

    代码分析

    分析上述代码,显然违背了面向对象语言几大原则中的:

    1单一职责原则:猫这个对象的内部还依赖其他对象细节,致使其本来的职责与其他对象的职责耦合在一起

    2开闭原则(Open-Closed Principle,OCP):即对扩展开放,对修改关闭,很显然,如果我们要扩展,例如改变上述动作的顺序,那么我们就不得不去修改猫内部代码

    上述代码问题的核心:猫这个对象很不稳定,在我们整个过程中,猫应该是独立存在,且不能够修改的

    观察者模式

    针对上面的问题场景,在面向对象语言中有一种适用的设计模式——观察者模式

    观察者模式将上述对象分为2类:

    主题(Subject):被关注的对象,当它的状态发生变化时,会触发观察者的反应,上述的猫就是一个主题,它发出猫叫这个状态变化的信号

    观察者(或订阅者,Observer):即关注主题的对象,当主题的状态发生变化,它们会做出反应,上述的狗,大人,婴儿,小偷都是观察者

    观察者模式采用的方式是将主题对观察者的直接依赖,转为对它们的抽象的依赖,具体代码如下:

    1    /// <summary>
    2     /// 观察者的抽象
    3     /// </summary>
    4     public interface IObserver
    5     {
    6         void Action();     
    7     }
    IObserver
     1     /// <summary>
     2     /// 主题
     3     /// </summary>
     4     public class Cat
     5     {
     6         /// <summary>
     7         /// 观察者集合
     8         /// </summary>
     9         private List<IObserver> _observerList = new List<IObserver>();
    10         /// <summary>
    11         /// 添加观察者
    12         /// </summary>
    13         /// <param name="observer"></param>
    14         public void AddObserver(IObserver observer)
    15         {
    16             _observerList.Add(observer);
    17         }
    18         /// <summary>
    19         /// 状态变化
    20         /// </summary>
    21         public void Miao()
    22         {
    23             Console.WriteLine("猫叫了..........");
    24 
    25             ///后续动作
    26             foreach (var item in _observerList)
    27             {
    28                 item.Action();
    29             }
    30         }
    31     }
    Subject
     1     public class Dog : IObserver
     2     {
     3         public void Wang()
     4         {
     5             Console.WriteLine("狗汪了..........");
     6         }
     7         public void Action()
     8         {
     9             Wang();
    10         }
    11     }
    12 
    13     public class Parents : IObserver
    14     {
    15         public void Wake()
    16         {
    17             Console.WriteLine("大人醒了..........");
    18         }
    19         public void Action()
    20         {
    21             Wake();
    22         }
    23     }
    24 
    25     public class Baby : IObserver
    26     {
    27         public void Cry()
    28         {
    29             Console.WriteLine("婴儿哭了..........");
    30         }
    31         public void Action()
    32         {
    33             Cry();
    34         }
    35     }
    36 
    37     public class Thief : IObserver
    38     {
    39         public void Run()
    40         {
    41             Console.WriteLine("小偷跑了..........");
    42         }
    43         public void Action()
    44         {
    45             Run();
    46         }
    47     }
    Observers
     1     class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             Cat cat = new Cat();
     6             cat.AddObserver(new Dog());
     7             cat.AddObserver(new Parents());
     8             cat.AddObserver(new Baby());
     9             cat.AddObserver(new Thief());
    10             cat.Miao();
    11             Console.ReadKey();
    12         }
    13     }
    Main

    通过观察者模式,主题与观察者之间的依赖被转移到了接口之上,面对新的扩展,完全不用再去修改主题,当我们需要添加新的观察者,只需要实现IObserver这个接口就可以,当我们需要修改顺序的时候,只需要在上端改变添加的顺序就可以

    观察者模式的类图:

    观察者模式存在的3种角色:

    1主题角色(Cat):被关注的对象

    2抽象观察者角色(IObserver):具体观察者角色的抽象

    3具体观察者角色(Dog,Parents,Baby,Thief):关注主题的对象,在主题状态改变后,作出响应

    Csharp下更优选择

    相比于上述使用观察者模式解决问题,在.Net里有更加优秀的解决方案,那就是委托事件

    同样是上述这个问题,使用委托事件来解决,代码如下

     1     public class Cat
     2     {
     3         public event Action MiaoEvent;
     4         public void Miao()
     5         {
     6             Console.WriteLine("猫叫了..........");
     7 
     8             MiaoEvent.Invoke();
     9         }
    10     }
    Subject
     1    public class Dog
     2     {
     3         public void Wang()
     4         {
     5             Console.WriteLine("狗汪了..........");
     6         }
     7     }
     8 
     9     public class Parents
    10     {
    11         public void Wake()
    12         {
    13             Console.WriteLine("大人醒了..........");
    14         }
    15     }
    16 
    17     public class Baby
    18     {
    19         public void Cry()
    20         {
    21             Console.WriteLine("婴儿哭了..........");
    22         }
    23     }
    24 
    25     public class Thief
    26     {
    27         public void Run()
    28         {
    29             Console.WriteLine("小偷跑了..........");
    30         }
    31     }
    ObjectForAction
     1     class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             Cat cat = new Cat();
     6             cat.MiaoEvent += new Dog().Wang;
     7             cat.MiaoEvent += new Parents().Wake;
     8             cat.MiaoEvent += new Baby().Cry;
     9             cat.MiaoEvent += new Thief().Run;
    10             cat.Miao();
    11             Console.ReadKey();
    12         }
    13     }
    Main

     使用观察者模式,主题内部维护的是一堆观察者的抽象对象,使用事件的方式,主题内部维护的是一张方法列表

    适用场景和优劣势

    当存在一对多的依赖关系,且需要监听状态变化的时候,观察者模式是一个很好的解决方案,例如:服务订阅通知,警报监控等等

    优势:

    1隔离了对象之间的直接依赖,降低了程序的耦合度

    2增加了程序的可读性,方便了维护和扩展

    3不需要熟悉观察者的细节详情,只用实现接口就可以

    劣势:

    1增加了程序的复杂度,设计模式的通病

    2观察者模式的效率是个问题,一个后续动作出现问题,会堵塞整个过程

    出自:博客园-半路独行

    原文地址:https://www.cnblogs.com/banluduxing/p/9279571.html

    本文出自于http://www.cnblogs.com/banluduxing 转载请注明出处。

  • 相关阅读:
    超级简单:一步一步教你创建一小型的asp.net mvc 应用程序
    asp.net AJAX 验证用户名是否存在 Jquery
    生成缩略图、为图片添加文字水印、图片水印的类
    图Graph
    [转]Implementing a Generic Binary Tree in C#
    .net C#数据结构
    Why HTML5 is worth your time
    跳跃表SkipList
    C# LockFreeStack类
    [转]泛型弱引用
  • 原文地址:https://www.cnblogs.com/banluduxing/p/9279571.html
Copyright © 2011-2022 走看看