23种设计模式+额外常用设计模式汇总 (持续更新)

观察者模式


高中的时候,班里有个两个同学太困了,就钻到桌子地下睡觉,结果被班主任抓包,打断了跟拖把,虽然面临高考还能这么淡定也是个人才。
怎么回事呢?
刘某被老师长期罚坐在门外上课!于是郑某每天帮刘某买饭,刘某成为了郑某的眼线,看到班主任来就把他叫起来。这样相安无事过了几天,然而事实证明刘某是靠不住的,今天刘某也睡着了,然后班主任亲自叫醒了刘某,然后带着刘某叫醒了班里熟睡的郑某,这样刘郑二人双双被打,直到拖把杆被打断。最后一个体育生郑dh跑进了中国矿业大学,另一个睡着了没离开又复读了一年!
这不就是观察者模式吗?
你可能认为刘某是观察者,其实郑某才是观察者,他观察刘某的动态,然后做出反馈,有点违背我们平时的理解。啪~ 啪 ~ 啪~!请看下文!
  
观察者模式又叫做:

  • 模型-视图(Model/View)模式
  • 源-监听器(Source/Listener)模式
  • 从属者(Dependents)模式

脑海中立刻闪现了《Head First设计模式》里讲的:

Publishers + Subscribers = Observer Pattern

他还应该叫发布订阅模式?但是确实不是,之前我混为一谈确实不对!这篇文章比较详细的讲解他们两个区别,并给出了源代码及实例,有兴趣的可以看一下。
发布者订阅者模式到底是个啥?看这!

意图:

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

一个软件系统常常要求在某一个对象的状态发生变化的时候,某些其它的对象做出相应的改变。做到这一点的设计方案有很多,是为了使系统能够易于复用,应该选择低耦合度的设计方案为了使系统能够易于复用,应该选择低耦合度的设计方案。

减少对象之间的耦合有利于系统的复用,但是同时设计师需要使这些低耦合度的对象之间能够维持行动的协调一致,保证高度的协作( Collaboration)。观察者模式是满足这一要求的各种设计方案中最重要的一种。

主要解决:

一个对象状态改变给其他对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。

何时使用:

一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。

如何解决:

使用面向对象技术,可以将这种依赖关系弱化,从而降低耦合性,避免循环观察形成死锁。

关键代码:

在抽象类里有一个 ArrayList 存放观察者们。

UML图:

观察者模式(Observer), 定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新。UML结构图如下:

优点:
  • 1.观察者和被观察者是抽象耦合的。
  • 2.建立一套触发机制:
    • 观察者模式实现了动态联动
    • 观察者模式支持广播通信。被观察者会向所有的登记过的观察者发出通知。
缺点:
  1. 可能存在无用的操作:
    由于采用广播模式,不管观察者是否需要,都会被通知调用Update()方法!
  2. 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
  3. 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

使用场景:

  • 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
  • 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
  • 一个对象必须通知其他对象,而并不知道这些对象是谁。
  • 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。

注意事项

目标和观察者之间的关系:

  • 典型的一对多的关系

单向依赖:

  • 观察者依赖于目标

触发通知的时机:

  • 完成了状态维护后触发

相互观察:

  • A、B观察C,B、C观察A(两套观察模式)
  • 注意死循环

通知的顺序

  • 绝对不要依赖于通知的顺序,多个观察者之间的功能是平行的,相互不应该有先后的依赖关系

实现:

抽象主题(Subject)角色:
  • 一个目标可以被多个观察者观察
  • 目标提供对观察者注册和退订的维护
  • 当目标的状态发生变化时,目标负责通知所有注册的、有效地观察者

首先定义一个观察者数组,并实现增、删及通知操作。它的职责很简单,就是定义谁能观察,谁不能观察,用Vector是线程同步的,比较安全,也可以使用ArrayList,是线程异步的,但不安全。

public class Subject {//观察者数组private Vector<Observer> oVector = new Vector<>();//增加一个观察者public void addObserver(Observer observer) {this.oVector.add(observer);}//删除一个观察者public void deleteObserver(Observer observer) {this.oVector.remove(observer);}//通知所有观察者public void notifyObserver() {for(Observer observer : this.oVector) {observer.update();}}     }
抽象观察者Observer
  • 为所有的具体观察者定义一个接口,在得到主题的通知时更新自己。这个接口叫做更新接口。
  • 抽象观察者角色一般用一个抽象类或者一个接口实现。在这个示意性的实现中,更新接口只包含一个方法(即Update()方法),这个方法叫做更新方法。
 public interface Observer {//更新public void update();
}
具体主题 (ConcreteSubject)

继承Subject类,在这里实现具体业务,在具体项目中,该类会有很多变种。
将有关状态存入具体现察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色又叫做具体被观察者角色(Concrete Observable)具体主题角色通常用一个具体子类实现。

 public class ConcreteSubject extends Subject {//具体业务public void doSomething() {//...super.notifyObserver();}}
具体观察者(ConcreteObserver)

具体现察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态相协调。如果需要,具体现察者角色可以保存一个指向具体主题对象的引用。具体观察者角色通常用一个具体子类实现。

 public class ConcreteObserver implements Observer {@Overridepublic void update() {System.out.println("收到消息,进行处理");}}
Client客户端

首先创建一个被观察者,然后定义一个观察者,将该被观察者添加到该观察者的观察者数组中,进行测试。

   public class Client {public static void main(String[] args) {//创建一个主题ConcreteSubject subject = new ConcreteSubject();//定义一个观察者Observer observer = new ConcreteObserver();//观察subject.addObserver(observer);//开始活动subject.doSomething();}}

观察者模式的应用

在实际应用中,抽象观察者Observer在C#和java中都已经被实现,我们可以直接使用。
  • Java中的观察者模式
    java.util.Observable,实现了大部分我们需要的目标的功能,还有一个接口Observer,其中定义了update方法,就是观察者的接口。在java9以后被弃用,弃用原因,后续将会填坑通过监听来重新实现观察者模式!
  • C#的Observer模式
    实际上在C#中实现Observer模式没有这么辛苦,.NET中提供了DelegateEvent机制,我们可以利用这种机制简化Observer模式。基于.NET简化的观察者模式。

举个例子:
那天博主的股票上市了,你们买了我的股票,我的股票涨了跌了得通知你们,我们就按照这个写一个。

package 观察者模式;public interface Observer {public void update(Object c);
}
package 观察者模式;import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Vector;public class Subject {private Vector<Observer> oVector;public Subject() {oVector=new  Vector<Observer>();}public void addObserver(Observer observer) {this.oVector.add(observer);}public void deleteObserver(Observer observer) {this.oVector.remove(observer);}public void notifyObserver() {SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Date d = new Date( );sf.format(d);for (Observer observer : this.oVector) {observer.update(d);}}
}
package 观察者模式;public class Share_Observer implements Observer {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}public void update(Object c) {System.out.println(name+"已更新股票数据"+c);}}
package 观察者模式;public class Shares_Subject extends Subject {public void RealTime_Update() {super.notifyObserver();}}
package 观察者模式;public class Client {public static void main(String[] args) {Shares_Subject subject = new Shares_Subject();Share_Observer observer = new Share_Observer();observer.setName("张俊浩的A股");subject.addObserver(observer);subject.RealTime_Update();}
}

写在最后:
我叫风骨散人,名字的意思是我多想可以不低头的自由生活,可现实却不是这样。家境贫寒,总得向这个世界低头,所以我一直在奋斗,想改变我的命运给亲人好的生活,希望同样被生活绑架的你可以通过自己的努力改变现状,深知成年人的世界里没有容易二字。目前是一名在校大学生,预计考研,热爱编程,热爱技术,喜欢分享,知识无界,希望我的分享可以帮到你!
如果有什么想看的,可以私信我,如果在能力范围内,我会发布相应的博文!
谢谢大家的阅读!

『设计模式』以为是个王者,后来班主任来了!设计模式--二五仔的观察者模式相关推荐

  1. 『设计模式』80年代的人们就已经领悟了设计模式-- 发布者/订阅者模式 (包括发布者/订阅者模式和观察者模式的区别)

    23种设计模式+额外常用设计模式汇总 (持续更新) 发布-订阅模式 在软件架构中,发布订阅是一种消息范式,消息的发送者(称为发布者)不会将消息直接发送给特定的接收者(称为订阅者).而是将发布的消息分为 ...

  2. 『设计模式』之小试牛刀

    为了更好的学习设计模式,以及督促自己完成设计模式的学习,现提笔为记. 怎么的,每周至少也要学一个设计模式!!! 恳请大家的监督和不吝赐教,共同学习和进步! 内容主要参考自<设计模式之禅>以 ...

  3. 『数据库』这篇数据库的文章真没人看--数据库完整性

    『数据库』 朴实无华且枯燥的数据库教程–入门必看!(不收藏,真的吃亏了) 文章目录 实体完整性 参照完整性 用户定义的完整性 完整性约束命名子句 域中的完整性限制 触发器 激活触发器 删除触发器 小结 ...

  4. 『数据库』无聊到爆炸的数据库文章--数据库的安全性

    『数据库』 朴实无华且枯燥的数据库教程–入门必看!(不收藏,真的吃亏了) 文章目录 计算机安全性概述 数据库安全性控制 视图机制 审计(Audit) 数据加密 统计数据库安全性 问题的提出 数据库的一 ...

  5. 『数据库』朴实无华且枯燥的数据库文章--关系数据理论

    『数据库』 朴实无华且枯燥的数据库教程–入门必看!(不收藏,真的吃亏了) 文章目录 问题的提出 规范化 数据依赖的公理系统 模式的分解 小结 问题的提出 一.概念回顾 关系:描述实体.属性.实体间的联 ...

  6. 『数据库』朴实无华的数据库多表查询,连接查询、笛卡尔积

    『数据库』 朴实无华且枯燥的数据库教程–入门必看!(不收藏,真的吃亏了) 文章目录 一.交 二.并 三.差 四.笛卡尔积 五.连接查询 一.交 (会用到连接运算,固定写法,连接运算在下面不用着急看) ...

  7. 『数据库』朴实无华的数据库绪论

    『数据库』 朴实无华且枯燥的数据库教程–入门必看!(不收藏,真的吃亏了) 文章目录 数据库系统概述 数据模型 概念模型 数据库系统结构 数据库系统的组成 数据库系统概述 一.四个基本概念 1.数据(D ...

  8. 『电子书』分享一波码农必备编程开发类书籍[转]

    分享一些书籍 看到书籍很多,感觉很不错,就收藏下来了,是百度盘的连接,失效的可以评论一下以此更新一下连接. 书籍清单 Python编程快速上手 细说PHP(第2版) Python核心编程(第3版) L ...

  9. [日推荐] 『Streeter』极乐商店邀你一起来尬舞啊!-store.dreawer.com

    2019独角兽企业重金招聘Python工程师标准>>> 你听的舞蹈有哪些?Jazz?Poppin?Hiphop?现代舞?民族舞?... 今天推荐一款小程序『Streeter』,几乎包 ...

最新文章

  1. QPS过万,redis大量连接超时怎么解决?
  2. springboot事务回滚源码_Spring Boot中的事务是如何实现的
  3. oracle和ibatis学习
  4. JAVA模拟HTTP post请求上传图片
  5. 蓝桥杯--算法训练 表达式计算
  6. 2020.8.26广联达笔试第二题——魔法师四种元素平衡(Python)
  7. oc32--构造方法1
  8. docker rabbitmq php扩展,Docker开启RabbitMQ延时消息队列
  9. (priority_queue)自定义优先级
  10. 阿里云OSS浏览图片报403错误的解决方法
  11. 关于搭建k8s集群遇到的问题与解决方法
  12. qt导出word模板(模块化程序,直接调用保存数据到指定路径)
  13. 英特尔 11 代酷睿桌面酷睿 i9-11900K登场
  14. android播放系统音效,Android用SoundPool播放音效
  15. OSPF多实例路由防环检测功能介绍
  16. 『NLP打卡营』实践课5:文本情感分析
  17. 试卷代号:4022 2021年春季学期期末统一考试金融风险概论 试题(开卷)
  18. css旋转,附源代码
  19. mac os linux pageup pagedown,教你巧用Mac上的Page UpDown键
  20. webots仿真车轮打滑问题解决

热门文章

  1. 详解C++17下的string_view
  2. android开发之Glide加载图片之url转bitmap的方法
  3. Android开发之Android Studio第三方库的六种依赖讲解说明
  4. 学校拥有计算机清单和所放位置说明,大学计算机基础期末考试指南(2011)
  5. Swift--基本数据类型(一)
  6. PHP爬虫音乐,PHPCrawl爬虫库实现抓取酷狗歌单
  7. java -jar 找不到引用类_怎么解决java -jar找不到主类问题
  8. Intellij IDEA 新建一个EJB工程(三)
  9. 输出目录文件被多个中间文件输出目录相同的工程包含
  10. Web学习之跨域问题及解决方案