经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » 设计模式 » 查看文章
通俗易懂设计模式解析——观察者模式
来源:cnblogs  作者:小世界的野孩子  时间:2019/10/11 10:11:33  对本文有异议

前言

  今天我们一起看看这个观察者模式,这个模式简单来说就是一个发布订阅类似的模式。按照名字来理解也就是存在一个观察者和一个被观察者。说几个例子给大家听,大家应该就明白了。例如在我们现在通过银行卡支付之后,会收到银行发过来的提示信息。例如当我们话费余额或者流量不足之时也会收到提示信息。这其中的逻辑帮我们理解观察者模式。当我们观察的一个对象发送变化之时就会触发某一机制。然后做出一系列的措施。

观察者模式介绍

一、来由

  在软件系统中我们经常会遇到对象之间存在一对多的关系,当一个对象被修改时,将会自动通知其依赖的对象。当然如果这些依赖关系过于紧密对于系统来说又不好抵御其变化。所以我们又需要实现其结构的松耦合。

二、意图

  定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

三、案例图

 

四、观察者代码示例

看上面的案例图、我们来细细说下这其中的四种角色:

抽象主题角色:将所有的观察者引用保存在一个列表,同时包含增加删除观察者的操作,包含调用抽象观察者的操作方法。

具体主题角色:实现其抽象主题的抽象方法。

抽象观察者:为所有的具体观察者定义一个接口,在得到主题通知时更新自己。

具体观察者:实现抽象观察者定义的接口,是自身的状态与主题的状态相对应。

到这里我们简单的介绍了下观察这模式的原理。我们接下来使用手机话费不足时短信提醒这一个案例来讲述观察者模式的代码示例吧,当我们手机话费低于或小于10元的时候,将会触发变化更新提示:

 

  1. namespace Observer_Pattern
  2. {
  3. class ObserverPattern
  4. {
  5. }
  6. /// <summary>
  7. /// 抽象主题角色(将所有观察者对象的引用保存在一个列表中、含有增加和删除观察者对象操作、包含调用抽象观察者的变更操作)
  8. /// </summary>
  9. public abstract class Subject
  10. {
  11. internal List<Observer> observers ;
  12. internal int Balance;
  13. /// <summary>
  14. /// 保存所有观察者对象
  15. /// </summary>
  16. public Subject(int balance)
  17. {
  18. observers = new List<Observer>();
  19. Balance = balance;
  20. }
  21. /// <summary>
  22. /// 增加观察者对象
  23. /// </summary>
  24. public abstract void Adds(Observer observer);
  25. /// <summary>
  26. /// 删除观察者对象
  27. /// </summary>
  28. public abstract void Removes(Observer observer);
  29. /// <summary>
  30. /// 通知观察者变化
  31. /// </summary>
  32. public void Notice()
  33. {
  34. foreach (var item in observers)
  35. {
  36. if (item!=null)
  37. {
  38. item.Change(this);
  39. }
  40. }
  41. }
  42. }
  43. /// <summary>
  44. /// 抽象观察者(为所有具体观察者提供了一个当主题通知是变更自己的操作)
  45. /// </summary>
  46. public abstract class Observer
  47. {
  48. public abstract void Change(Subject Item);
  49. }
  50. /// <summary>
  51. /// 具体主题角色,实现抽象角色抽象方法
  52. /// </summary>
  53. public class CallChargeSubject : Subject
  54. {
  55. public CallChargeSubject( int balance) : base( balance )
  56. {
  57. }
  58. public override void Adds(Observer observer)
  59. {
  60. observers.Add(observer);
  61. }
  62. public override void Removes(Observer observer)
  63. {
  64. observers.Remove(observer);
  65. }
  66. }
  67. /// <summary>
  68. /// 具体观察者
  69. /// </summary>
  70. public class CallChargeObserver : Observer
  71. {
  72. internal string Name;
  73. public CallChargeObserver(string name)
  74. {
  75. Name = name;
  76. }
  77. public override void Change(Subject Item)
  78. {
  79. Console.WriteLine($"{Name}您好,您当前话费余额为:{Item.Balance},为了避免后续为您带来不便请及时充值!");
  80. }
  81. }
  82. }

 

  1. namespace Observer_Pattern
  2. {
  3. class Program
  4. {
  5. static void Main(string[] args)
  6. {
  7. Subject subject = new CallChargeSubject(10);
  8. subject.Adds(new CallChargeObserver("张三"));
  9. subject.Adds(new CallChargeObserver("李四"));
  10. subject.Notice();
  11. }
  12. }
  13. }

 

使用场景及优缺点

一、使用场景

1、一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用

2、当对一个对象的改变需要同时做出改变的时候,而又不知道具体有多少对象需要待改变的情况下。

3、一个对象必须通知其他对象,但是并不知道这些对象是谁。

二、优点

1、观察者和被观察者直接松耦合,依赖于抽象而不是具体实现

2、建立了一套触发的订阅发布机制。

三、缺点

1、如果一个被观察者有很多观察者的话,变化通知所有观察者需要花费很多的时间

2、观察者和被观察者之间有循环依赖的话,变化触发之后会造成循环调用。会导致系统崩溃。

3、观察者只知道被观察者发生了变化,但是并不知道被观察者是如何发生变化的。

总结

  到这里我们就介绍完了观察者模式,这个模式是一种一对多的关系依赖。如果不使用抽象主题角色和抽象观察者也是可以实现监控话费的任务的,但是这样会造成主题角色和观察者角色紧耦合。观察者模式主要实现的就是解耦代码,实现依赖倒置原则。依赖于抽象而不是具体实现。再说观察者模式、在我前面的文章又写过委托与事件,其中提到了事件基于委托,为委托提供了一种发布/订阅机制。我们仔细研究可以发现观察者模式和委托还是较为相似的。

 


 这个社会是存在不公平的,不要抱怨,因为没有用!人总是在反省中进步的!

     C#设计模式系列目录

     欢迎大家扫描下方二维码,和我一起踏上设计模式的闯关之路吧!

  

 

原文链接:http://www.cnblogs.com/hulizhong/p/11649442.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号