设计模式-观察者模式
来源:互联网 发布:淘宝分享链接打不开 编辑:程序博客网 时间:2024/05/17 09:22
1.观察者模式介绍
观察者模式是一个使用频率非常高的模式,它最常用的是GUI系统、订阅-发布系统。因为这个模式的重要作用就是解耦,将被观察者和观察者解耦,使得它们之间的依赖性更小,甚至做到毫无依赖。2.观察者模式的定义
定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。3.观察者模式的使用场景
关联行为场景
关联行为是可以拆分的,而不是“组合”的关系事件多级触发场景
跨系统的消息交换场景
如 消息队列、事件总线的处理机制4.观察者模式的UML类图
5.具体实现
抽象主题角色类
/** * 抽象主题类 * Created by Teaphy * 2016/4/24. */ public abstract class Subject { // 用来保存注册的观察者对象 private List<Observer> listsObserver = new ArrayList<>(); /** * 注册观察者对象 * @param observer 观察者对象 */ public void attach(Observer observer){ listsObserver.add(observer); System.out.println("Attached an observer"); } /** * 删除观察者对象 * @param observer 观察者对象 */ public void detach(Observer observer){ listsObserver.remove(observer); } /** * 通知所有注册的观察者对象 */ public void nodifyObservers(String newState){ for(Observer observer : listsObserver){ observer.update(newState); } } }
具体主题角色类
/** * 具体主题类 * Created by Teaphy * 2016/4/24. */ public class ConcreteSubject extends Subject { private String msg; public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public void publish(String msg) { nodifyObservers(msg); } }
抽象观察者角色类
/** * 抽象观察者角色类 * Created by Teaphy * 2016/4/24. */ public interface Observer { /** * 更新接口 * Created By * on 2016/4/24 * @param msg 更新信息 */ void update(String msg); }
具体观察者角色
/** * 具体观察者角色 * Created by Teaphy * 2016/4/24. */ public class ObserverA implements Observer { /** * 更新观察者信息 */ public void update(String msg) { System.out.println("ObserverA - msg = [" + msg + "]"); } } /** * 具体观察者角色 * Created by Teaphy * 2016/4/24. */ public class ObserverB implements Observer { /** * 更新观察者信息 */ public void update(String msg) { System.out.println("ObserverB - msg = [" + msg + "]"); } } /** * 具体观察者角色 * Created by Teaphy * 2016/4/24. */ public class ObserverC implements Observer { /** * 更新观察者信息 */ public void update(String msg) { System.out.println("ObserverC - msg = [" + msg + "]"); } }
测试
/** * Created by Teaphy * 2016/4/24. */ public class TestObserver { public static void main(String[] args) { //创建主题对象 ConcreteSubject cs = new ConcreteSubject(); // 添加观察者对象 cs.attach(new ObserverA()); cs.attach(new ObserverB()); cs.attach(new ObserverC()); // 发布新版本 cs.publish("英语"); } }
输出结果
Attached an observer Attached an observer Attached an observer ObserverA - msg = [英语] ObserverB - msg = [英语] ObserverC - msg = [英语]
6.推模型和拉模型
在观察者模式中,又分为推模型和拉模型两种方式。● 推模型
主题对象向观察者推送主题的详细信息,不管观察者是否需要,推送的信息通常是主题对象的全部或部分数据。
●拉模型
主题对象在通知观察者的时候,只传递少量信息。如果观察者需要更具体的信息,由观察者主动到主题对象中获取,相当于是观察者从主题对象中拉数据。一般这种模型的实现中,会把主题对象自身通过update()方法传递给观察者,这样在观察者需要获取数据的时候,就可以通过这个引用来获取了。
根据上面的描述,发现前面的例子就是典型的推模型,下面给出一个拉模型的实例。
拉模型的抽象观察者类
拉模型通常都是把主题对象当做参数传递。/** * 抽象观察者角色类 * Created by Teaphy * 2016/4/24. */ public interface ObserverPull { /** * 更新接口 * Created By * on 2016/4/24 * @param subjectPull 传入主题对象,方面获取相应的主题对象的状态 */ void update(SubjectPull subjectPull); }
拉模型的具体观察者类
/** * 具体观察者角色 * Created by Teaphy * 2016/4/24. */ public class ObserverPullA implements ObserverPull { private String msg; public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } /** * 更新观察者信息 */ public void update(SubjectPull subjectPull) { setMsg(((ConcreteSubjectPull)subjectPull).getMsg()); } }
拉模型的抽象主题类
拉模型的抽象主题类主要的改变是nodifyObservers()方法。在循环通知观察者的时候,也就是循环调用观察者的update()方法的时候,传入的参数不同了/** * 抽象主题类 * Created by Teaphy * 2016/4/24. */ public abstract class SubjectPull { // 用来保存注册的观察者对象 private List<ObserverPull> listsObserver = new ArrayList<>(); /** * 注册观察者对象 * @param observer 观察者对象 */ public void attach(ObserverPull observer){ listsObserver.add(observer); System.out.println("Attached an observer"); } /** * 删除观察者对象 * @param observer 观察者对象 */ public void detach(ObserverPull observer){ listsObserver.remove(observer); } /** * 通知所有注册的观察者对象 */ public void nodifyObservers(){ for(ObserverPull observer : listsObserver){ observer.update(this); } } }
拉模型的具体主题类
跟推模型相比,有一点变化,就是调用通知观察者的方法的时候,不需要传入参数了/** * 具体主题类 * Created by Teaphy * 2016/4/24. */ public class ConcreteSubjectPull extends SubjectPull { private String msg; public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public void publish(String msg) { setMsg(msg); //状态发生改变,通知各个观察者 nodifyObservers(); } }
测试
/** * Created by Teaphy * 2016/4/24. */ public class TestObserverPull { public static void main(String[] args) { //创建主题对象 ConcreteSubjectPull cs = new ConcreteSubjectPull(); ObserverPullA observerPullA = new ObserverPullA(); ObserverPullB observerPullB = new ObserverPullB(); ObserverPullC observerPullC = new ObserverPullC(); // 添加观察者对象 cs.attach(observerPullA); cs.attach(observerPullB); cs.attach(observerPullC); // 发布新版本 cs.publish("英语周报20160414期"); System.out.println("ObserverPullA - " + observerPullA.getMsg()); System.out.println("ObserverPullB - " + observerPullB.getMsg()); System.out.println("---------------------------------"); // 发布新版本 cs.publish("英语周报20160424期"); System.out.println("ObserverPullA - " + observerPullA.getMsg()); System.out.println("ObserverPullC - " + observerPullC.getMsg()); } }
输出结果
ObserverPullA - 英语周报20160414期 ObserverPullB - 英语周报20160414期 --------------------------------- ObserverPullA - 英语周报20160424期 ObserverPullC - 英语周报20160424期
7.两种模式的比较
1.推模型是假定主题对象知道观察者需要的数据;而拉模型是主题对象不知道观察者具体需要什么数据,没有办法的情况下,干脆把自身传递给观察者,让观察者自己去按需要取值。
2.推模型可能会使得观察者对象难以复用,因为观察者的update()方法是按需要定义的参数,可能无法兼顾 没有考虑到的使用情况。这就意味着出现新情况的时候,就可能提供新的update()方法,或者是干脆重新实现观察者;而拉模型就不会造成这样的情况,因为拉模型下,update()方法的参数是主题对象本身,这基本上是主题对象能传递的最大数据集合了,基本上可以适应各种情况的需要。
0 0
- 模式设计:观察者模式
- 设计模式-----观察者模式
- 设计模式-观察者模式
- 设计模式--观察者模式
- 设计模式:观察者模式
- 设计模式-----观察者模式
- 设计模式:观察者模式
- 设计模式-观察者模式
- 设计模式 观察者模式
- 设计模式-观察者模式
- 设计模式-【观察者模式】
- 设计模式-观察者模式
- 设计模式 -- 观察者模式
- 设计模式-观察者模式
- 【设计模式】观察者模式
- 设计模式- 观察者模式
- 设计模式- 观察者模式
- 设计模式--观察者模式
- 电压控制型开关电源的基本电路
- Servlet的生命周期
- Runtime Error R6016问题
- Udacity Code Review Suggestions
- 三种默认路由的区别ip default-gateway、ip default-network、ip route 0.0.0.0 0.0.0.0
- 设计模式-观察者模式
- Java “==”与“equals"的区别
- 加锁
- 白话空间统计二十一:密度分析(三)
- php数组操作方法
- android源代码编译
- 方便的自动Spring注解注入
- spring security 登录、权限管理配置
- 吴大大的小panpan1