观察者模式
2016-09-03 12:05
316 查看
观察者模式
观察者模式定义
观察者模式(Observer Pattern)也叫做发布订阅模式(Publish/subscribe),他是一个在项目中经常使用的模式,其定义如下:Define a one-to-many dependency between objects so that when one object changes state,all its dependents are notified and updated automatically(定义对象间一种一对多的依赖关系,使得每一个对象改变状态,则所有依赖与它的对象都会得到通知和被自动更新)。
简单实现
实现开发者模式我们首先举一个现实中的列子,大家上学的时候我们的老湿经常会给我们班级安排几个奸细(江湖传名“课代表”),让他们监视我们的动向,上课说话,打架,papapa这些奸细马上就会通知老湿,然后老湿就惩罚我们,好了这个就是一个观察者模式,以上讲到的这个场景有以下对象:老湿-观察者(teacher)
学生-被观察者(student)包括奸细
首先创建学生(被观察者)的接口,定义学生的一些动作
package design.observier.observer000; /** * 学生接口 * @author yanwenfei * */ public interface IStudent { //学生上课的时候在说话 public void speakOnStudy(); //papapa public void makeLove(); }
学生的实现类,把老湿安排课代表通过构造函数聚集到学生中,在学生活动的时候通过课代表调用update通知老湿
package design.observier.observer000; //学生实现类 public class Student implements IStudent { //聚集 一个奸细 private ITeacher teacher; //老湿安排了一个心腹到学生里面 public Student(ITeacher teacher) { this.teacher = teacher; } @Override public void speakOnStudy() { System.out.println("学生在学习的时候说话"); teacher.update("报告老湿:学生在学习的说话"); } @Override public void makeLove() { System.out.println("学生在papapa"); teacher.update("报告老湿:学生在papapa"); } }老湿接口,老湿响应的方法
package design.observier.observer000; /** * 观察者 * @author yanwenfei * */ public interface ITeacher { //被通知后的操作 public void update(String str); }
老湿的实现类,课代表告诉老湿后,打印了一句话
package design.observier.observer000; public class Teacher implements ITeacher { @Override public void update(String str) { System.out.println(str); System.out.println("老湿知道了"); } }
现在测试、
package design.observier.observer000; public class TestMain { public static void main(String[] args) { ITeacher teacher = new Teacher();//创建一个老湿的课代表 Student stu = new Student(teacher);//创建一个学生,并把课代表放进去 stu.speakOnStudy();//学生在说话 stu.makeLove();//学生在papapa } }
运行结果:
学生在学习的时候说话 报告老湿:学生在学习的说话 老湿知道了 学生在papapa 报告老湿:学生在papapa 老湿知道了
以上为观察者模式最简单的实现,把观察着聚集到被观察者中,当被观察者有活动的时候,观察者马上执行一个方法,这就是观察者模式。
但是实际情况不是这样的,不可能只有一个老湿需要监视,可能还有语文课代表,英语课代表、数学课代表等等,以上简单的实现不能很好的扩展,如果需要增加一个课代表那要改很多代码,所有是有毒代码,下来看看下一节观察者模式扩展
观察者模式扩展
为了很好的扩展,增加观察者对象,就需要做以下修改:增加 被观察者应该可以动态添加观察者
增加 被观察者应该可以动态删除观察者
增加 通知所有观察者
考虑以下 以上这些操作,应该所有被观察者通用的方法,不应该在具体的被观察者中实现,所以应该创建一个抽象类来实现这些操作,具体的被观察者应该只实现自己的动作比如 啪啪啪,
代码清单应该是:
AbstractStudentOverser(抽象学生被观察者)实现添加删除观察者并通知
IStudent (学生接口)
StudentA (学生实现类)
ITeacherOberser(观察者接口)
Teacher(老湿实现类)
下来具体实现
package design.observier.observer001; //观察者 可恶的老湿 public interface Teacher { //老湿知道消息后惩罚被观察的学生 public void update(Object o); }王老湿:
package design.observier.observer001; public class TeacherW implements Teacher { @Override public void update(Object o) { System.out.println("王老湿:"+o.toString()); } }
抽象的学生被观察者,创建一个动态数据存放所有的观察者,
package design.observier.observer001; import java.util.ArrayList; import java.util.List; /** * 抽象被观察的学生 * @author yanwenfei * */ public abstract class AbStractStudent { private final List<Teacher> teachers = new ArrayList<Teacher>(); //添加一个奸细 public void addSpy(Teacher t){ teachers.add(t); }; //删除一个奸细 public void removeSpy(Teacher t){ teachers.remove(t); }; //通知所有的奸细 public void notifyTeacher(Object o){ for (Teacher t:teachers){ t.update(o); } } }
package design.observier.observer001; public interface IStudent { //学生上课的时候在说话 public void speakOnStudy(); //papapa public void makeLove(); }
package design.observier.observer001; public class StudentA extends AbStractStudent implements IStudent{ @Override public void speakOnStudy() { System.out.println("学生A:学习的时候在说话.."); this.notifyTeacher("奸细:报告老湿,学生A在学习的时候说话"); } @Override public void makeLove() { System.out.println("学生A:在PAPAPA.."); this.notifyTeacher("奸细:报告老湿,学生A在AAA"); } }
package design.observier.observer001; public class TestMain { public static void main(String[] args) { StudentA stua = new StudentA();//学生A Teacher teacherW = new TeacherW(); stua.addSpy(teacherW); stua.makeLove(); stua.speakOnStudy(); StudentB stub = new StudentB();//学生B stub.addSpy(teacherW); stub.makeLove(); stub.speakOnStudy(); } }
执行结果
学生A:在PAPAPA.. 王老湿:奸细:报告老湿,学生A在AAA 学生A:学习的时候在说话.. 王老湿:奸细:报告老湿,学生A在学习的时候说话 学生B:在PAPAPA.. 王老湿:奸细:报告老湿,学生B在AAA 学生B:学习的时候在说话.. 王老湿:奸细:报告老湿,学生B在学习的时候说话
通过这次扩展改造之后,代码的扩展性就很好,如果需要添加一个被观察者,只需要添加一个学生类接触抽象类实现接口就可以,如果需要添加观察者,只需要添加一个teacher类就可以,而不需要修改代码,符合了封闭原则
观察者优化
我这里讲的观察者优化,实际上是换汤不换药,因为JDK本身已经实现了观察者模式java.util.Observable 被观察类 java.util.Observer 观察者
我们可以对以上代码作如下优化
IStudent 不用写了 没有变
学生A直接继承了JDK的Observer 而不需要自己创建
package design.observier.observer002; import java.util.Observable; public class StudentA extends Observable implements IStudent { @Override public void speakOnStudy() { System.out.println("学生A:开始说话了.."); super.setChanged(); super.notifyObservers("奸细:报告老湿,学生A在说话"); } @Override public void makeLove() { System.out.println("学生A:PAPAPA.."); super.setChanged(); super.notifyObservers("奸细:报告老湿,学生A在PAPAPA"); } }观察者老湿类也是继承了JDK的观察者类
package design.observier.observer002; import java.util.Observable; import java.util.Observer; public class TeacherA extends Observable implements Observer { @Override public void update(Observable o, Object arg) { System.out.println(arg.toString()); } }
package design.observier.observer002; public class TestMain { public static void main(String[] args) { StudentA a = new StudentA(); TeacherA bb = new TeacherA(); a.addObserver(bb); a.makeLove(); } }
执行结果:
学生A:在PAPAPA.. 王老湿:奸细:报告老湿,学生A在AAA 学生A:学习的时候在说话.. 王老湿:奸细:报告老湿,学生A在学习的时候说话 学生B:在PAPAPA.. 王老湿:奸细:报告老湿,学生B在AAA 学生B:学习的时候在说话.. 王老湿:奸细:报告老湿,学生B在学习的时候说话
结果是相同的,所以的JDK已经帮我们实现了很多设计模式和代码,所以学习对读源代码还是很有用的。
观察者模式优点
观察者和被观察者之间的是抽象耦合(扩展性好)建立了一套触发机制
观察者模式缺点
被观察者模式需要考虑运行的性能和效率,一个被观察着多个观察者,开发和调试就会比较复杂,而且在java中,消息通知是按照顺序执行的,如果一个观察者卡住,会影响所有的观察者。如果使用异步,那就更不好控制。观察者模式应用场景
跨系统的消息交换场景(消息对立的处理机制)事件多级触发场景
关联行为场景
观察者模式注意事项
广播链问题 (A 通知 B 通知 C通知D。。。。)异步处理问题 (通知如果采用异步)
如果以上有问题,希望指出改正,谢谢
设计模式虽然不是一门技术,但是对我们平时编程与阅读API很有帮助,个人也只是皮毛重点还是应用,欢迎大神们加群一起探讨 群号:167014883
相关文章推荐
- PropertyChangeListener简单理解
- 什么是设计模式
- 设计模式之创建型模式 - 特别的变量问题
- 设计模式之行为型模式 - 调用行为的传递问题
- 七、设计模式——装饰模式
- 设计模式总结
- 设计模式之创建型模式
- 浅谈设计模式的学习
- 设计模式---状态模式在web前端中的应用
- Ruby设计模式编程之适配器模式实战攻略
- 实例讲解Ruby使用设计模式中的装饰器模式的方法
- 设计模式中的模板方法模式在Ruby中的应用实例两则
- Ruby设计模式编程中对外观模式的应用实例分析
- 实例解析Ruby设计模式编程中Strategy策略模式的使用
- Ruby中使用设计模式中的简单工厂模式和工厂方法模式
- Ruby使用设计模式中的代理模式与装饰模式的代码实例
- 详解组合模式的结构及其在Ruby设计模式编程中的运用
- C# 设计模式系列教程-建造者模式
- C#编程中使用设计模式中的原型模式的实例讲解
- 使用设计模式中的工厂方法模式进行C#编程的示例讲解