java设计模式解析(1) Observer观察者模式
设计模式系列文章
|
java设计模式解析(1) Observer观察者模式
java设计模式解析(2) Proxy代理模式
java设计模式解析(3) Factory工厂模式
java设计模式解析(4) Singleton单例模式
java设计模式解析(5) Delegate委派模式
java设计模式解析(6) Strategy策略模式
java设计模式解析(7) Prototype原型模式
java设计模式解析(8) Template模版模式
java设计模式解析(9) Decorator装饰模式
java设计模式解析(10) Adapter适配模式
java设计模式解析(11) Chain责任链模式
|
主要内容 |
2、实现代码(Talk is cheap,Show me the code)
观察者设计模式在日常软件开发非常常见。比如MQ消息监听、ZooKeeper监听节点事件、Spring发布事件以完成容器初始化(后续会有分析)等。
度娘上对观察者模式有很多版本定义,个人觉得还是《设计模式之禅》定义比较全面,不愧设计模式宝典啊。先贴出来具体定义:
针对上面给出的几个关键对角色,补充一下自己的理解:
1)、Subject:被观察者,即事件的起源。一般在软件实现阶段是 接口 或者 抽象类
2)、Observer:观察者,即观察到事件发生则同步更新自身的状态。一般在软件实现阶段是 接口 或者 抽象类
2、实现代码(Talk is cheap,Show me the code)
《设计模式之禅》已经给出具体的代码实现部分,但是个人觉得过于标准化,现实软件落地肯定会对其进行改造,例如Spring发布事件机制(后续会有分析)。这里个人实现场景,欢迎拍砖:
定义:大学每个学期都会提前订阅该学期的课程,一个课程会被N多个学生订阅。假设某个数学课程任课老师变更之后,学生需要同步更新课程信息,实现自级联变更。
分析:此时可以看出来【课程】就是被观察者的角色,【学生】就是观察者的角色。当【课程】有变动即任课老师变更,需要及时通知【学生】。
Subject课程
/** * 课程 被观察的对象 * @author zhou.guangfeng on 2019/8/21 下午5:29 */ public interface Subject { void teacherChange(String teacherName) ; }
Student学生
/** * 学生 观察者 * @author zhou.guangfeng on 2019/8/21 下午5:29 */ public interface Student { void changeSubjectTeacherName(String teacherName) ; }
Observer监听 串联观察者 和 被观察者,同时实现被观察者接口
/** * 监听 串联观察者 和 被观察者。同时实现被观察者接口 * @author zhou.guangfeng on 2019/8/21 下午5:29 */ public class Observer implements Subject { private Subject subject ; private List<Student> studentList = new ArrayList<>() ; public Observer(Subject subject) { this.subject = subject; } @Override public void teacherChange(String teacherName) { subject.teacherChange(teacherName); studentList.forEach(student -> student.changeSubjectTeacherName(teacherName)); } /** * 动态注册观察者 * * @param * @return */ public void registerStudent(Student student){ System.out.println("动态注册观察者 --> " + student); studentList.add(student) ; } /** * 动态删除观察者 * * @param * @return */ public void removeStudent(Student student){ System.out.println("动态删除观察者 --> " + student); studentList.remove(student) ; } }
ObserverMain执行代码
public class ObserverMain { public static void main(String[] args) { // 被观察者 数学课程 Subject shuxue = new Subject() { @Override public void teacherChange(String teacherName) { System.out.println("数学课程 修改老师为 " + teacherName); } }; // 监听者 代理了被观察者 即 数学课程 Observer watcher = new Observer(shuxue) ; Student student = new Student() { @Override public void changeSubjectTeacherName(String teacherName) { System.out.println("学生A 修改老师为 " + teacherName); } } ; // 注册 观察者 watcher.registerStudent(student); watcher.registerStudent(new Student() { @Override public void changeSubjectTeacherName(String teacherName) { System.out.println("学生B 修改老师为 " + teacherName); } }); // 改变课程 watcher.teacherChange("华罗庚"); // 删除监听学生 watcher.removeStudent(student); // 改变课程 watcher.teacherChange("爱因斯坦"); } }
执行结果:
动态注册观察者 --> com.nancy.observer.ObserverMain$2@6f94fa3e 动态注册观察者 --> com.nancy.observer.ObserverMain$3@5e481248 数学课程 修改老师为 华罗庚 学生A 修改老师为 华罗庚 学生B 修改老师为 华罗庚 动态删除观察者 --> com.nancy.observer.ObserverMain$2@6f94fa3e 数学课程 修改老师为 爱因斯坦 学生B 修改老师为 爱因斯坦
(1)、由于触发观察者是顺序调用,如果观察者很多(例子中student群体特别多,触发时间很长)势必会有效率瓶颈,此时可以考虑使用线程池等异步进行。
(2)、关系广播链接不能太复杂,否则将难于维护。