设计模式笔记(六)——观察者模式
2018-04-09 00:00
162 查看
摘要: 前几天在做Spring的监听器时突然想到了观察者模式,这个也很重要。。。。
l 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
l 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
l 一个对象必须通知其他对象,而并不知道这些对象是谁。
l 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。
![](https://static.oschina.net/uploads/space/2018/0409/203806_9WnT_3041734.png)
气象局发布天气预报,学生和上班族根据天气做出相应反应。
内部维护一个{“晴天”, “下雨”, “雾霾”, “冰雹”, “狂风”, “暴雪”}
气象局要根据观测进行天气更新
updateWeather();
气象局要不断工作,不断观测天气:
死循环中每隔1-2秒执行一次
notifyWeather();
注意这里可以给气象局的weather只设置get方法,这样别人只能看
让学生每次都去看气象局的天气,也就是在notify方法中传入天气
这里使用简单if,else-if,else结构:
l 晴天——开心上学
l 下雨——打着雨伞上学
l 雾霾——开心的吸着毒上学
l 冰雹——学校门口砸了个大坑,不去上学
l 狂风——学校被吹走了,不去上学
l 暴雪——学校门口被雪埋了,不去上学
之后,在Client中编写:
发现这种方法实在太差,这样学生啥也别干了,光盯着天气预报算了。
而且,如果只是这样,会在客户端留下一个非常严重的问题:
因为气象局一直在观测天气,所以work()方法后面的代码永远无法执行。
运行之后发现会出现观察时间与气象局更新时间不匹配的bug。
问题:现在是人主动去关注天气,能不能让气象局播天气预报?
addStudent();
每次更新天气时,迭代学生列表,通知学生
到此为止,已经构成了观察者模式
l 下雨——打着雨伞上班
l 雾霾——带着消毒面具上班
l 冰雹——带着三级头盔上班
l 狂风——拖着大石头上班
l 暴雪——披着被子上班
发现在Client中不能addEmployee!
观察上班族和学生,他们都有一个共同的特点:
看天气预报!根据天气不同,作出不同的反应!
这属于行为——可以抽出一个接口(面向接口编程而不是实现类)
之后,在气象局中使用多态即可。
----当某个按钮被点击时,要通知另一些组件作出反应(如点击全选,所有复选框被选中)
但发现:GUI的事件监听机制是使用匿名内部类!
这种设计思路是:只要被通知的对象符合一定的特征即可!
这不就是匿名内部类的使用思路吗???(突然滑稽)
Observer类,Observable接口
![](https://static.oschina.net/uploads/space/2018/0409/204422_LAqm_3041734.png)
![](https://static.oschina.net/uploads/space/2018/0409/204456_V6TQ_3041734.png)
实现Observable接口的,都是被通知对象。
Observer本身就可以通知,当然可以继承Observer类,扩展功能。。。
1. 是什么——定义
定义对象间的一种一对多的依赖关系,让多个观察者同时监听某一个主题现象,当一个对象的状态发生改变时,会通知所有观察者对象,所有依赖于它的对象都得到通知并被自动更新。2. 为什么——特点
一个对象状态改变的同时,需要同时改变其他对象。3. 什么时候用——适用性
l 一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。l 一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
l 一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
l 一个对象必须通知其他对象,而并不知道这些对象是谁。
l 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。
4. UML图
![](https://static.oschina.net/uploads/space/2018/0409/203806_9WnT_3041734.png)
5. 怎么用——使用方法
需求:气象局发布天气预报,学生和上班族根据天气做出相应反应。
5.1 气象局
设计WeatherStation:内部维护一个{“晴天”, “下雨”, “雾霾”, “冰雹”, “狂风”, “暴雪”}
气象局要根据观测进行天气更新
updateWeather();
气象局要不断工作,不断观测天气:
死循环中每隔1-2秒执行一次
updateWeather() { while(true){ //更新天气 } }
5.2 学生
学生要设计看天气预报的方法notifyWeather();
注意这里可以给气象局的weather只设置get方法,这样别人只能看
让学生每次都去看气象局的天气,也就是在notify方法中传入天气
这里使用简单if,else-if,else结构:
l 晴天——开心上学
l 下雨——打着雨伞上学
l 雾霾——开心的吸着毒上学
l 冰雹——学校门口砸了个大坑,不去上学
l 狂风——学校被吹走了,不去上学
l 暴雪——学校门口被雪埋了,不去上学
public void notifyWeather(String weather) { if ("晴天".equals(weather)) { System.out.println(name + "开开心心的上学!"); }else if ("下雨".equals(weather)) { System.out.println(name + "打伞上学!"); }else if ("雾霾".equals(weather)) { System.out.println(name + "开心的吸着毒上学!"); }else if ("冰雹".equals(weather)) { System.out.println("学校门口被砸了个坑,不去了!"); }else if ("下雪".equals(weather)) { System.out.println("学校门口被雪埋了,不去上学!"); }else if ("狂风".equals(weather)) { System.out.println("学校被吹走了,没学上了!"); } }
之后,在Client中编写:
while(true){ student.notifyWeather(station.getWeather()); }
发现这种方法实在太差,这样学生啥也别干了,光盯着天气预报算了。
而且,如果只是这样,会在客户端留下一个非常严重的问题:
因为气象局一直在观测天气,所以work()方法后面的代码永远无法执行。
5.3 解决代码无法执行的bug
new Thread(new Runnable() { @Override public void run() { while(true){ updateWeather(); int s = random.nextInt(1000)+1000; try { Thread.sleep(s); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start();
运行之后发现会出现观察时间与气象局更新时间不匹配的bug。
问题:现在是人主动去关注天气,能不能让气象局播天气预报?
5.4 气象局维护学生
新建一个方法:addStudent();
每次更新天气时,迭代学生列表,通知学生
public void updateWeather() throws Exception { while (true) { weather = weathers[random.nextInt(weathers.length)]; System.out.println("当前的天气是:" + weather); for (Student student : students) { student.notifyWeather(weather); } Thread.sleep(random.nextInt(1000) + 1000); } }
到此为止,已经构成了观察者模式
5.5 新增上班族
l 晴天——开心上班l 下雨——打着雨伞上班
l 雾霾——带着消毒面具上班
l 冰雹——带着三级头盔上班
l 狂风——拖着大石头上班
l 暴雪——披着被子上班
public void notifyWeather(String weather) { if ("晴天".equals(weather)) { System.out.println(name + "开开心心的上班!"); }else if ("下雨".equals(weather)) { System.out.println(name + "打伞上班!"); }else if ("雾霾".equals(weather)) { System.out.println(name + "戴着防毒面具上班!"); }else if ("冰雹".equals(weather)) { System.out.println(name + "戴着三级头去上班"); }else if ("下雪".equals(weather)) { System.out.println(name + "披着被子去上班"); }else if ("狂风".equals(weather)) { System.out.println(name + "拖着大石头上班!"); } }
5.6 气象局维护上班族
试着在Client中创建Employee的对象。。。发现在Client中不能addEmployee!
观察上班族和学生,他们都有一个共同的特点:
看天气预报!根据天气不同,作出不同的反应!
这属于行为——可以抽出一个接口(面向接口编程而不是实现类)
5.7 抽取被通知者
public interface Observable { public void notifyWeather(String weather); }
之后,在气象局中使用多态即可。
5.8 新增天气预报软件,抽取天气通知类型(观察者)
无需多言,与上面的思路完全一致。6. 实际应用
其实,Java的GUI实现的组件事件监听,本质就是观察者模式。----当某个按钮被点击时,要通知另一些组件作出反应(如点击全选,所有复选框被选中)
但发现:GUI的事件监听机制是使用匿名内部类!
button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.out.println("我被点击了。。。"); } });
这种设计思路是:只要被通知的对象符合一定的特征即可!
这不就是匿名内部类的使用思路吗???(突然滑稽)
7. Java中的观察者模式支持
翻开java.util包,可以发现一个类和一个接口:Observer类,Observable接口
![](https://static.oschina.net/uploads/space/2018/0409/204422_LAqm_3041734.png)
![](https://static.oschina.net/uploads/space/2018/0409/204456_V6TQ_3041734.png)
实现Observable接口的,都是被通知对象。
Observer本身就可以通知,当然可以继承Observer类,扩展功能。。。
相关文章推荐
- 设计模式学习笔记-观察者模式(Observer)
- 设计模式C++学习笔记之十六(Observer观察者模式)
- 设计模式学习笔记(二)- -观察者模式
- 设计模式笔记8: 观察者模式
- 设计模式学习笔记(二)之观察者模式(Observer)
- 设计模式笔记之观察者模式(Observer Patterns)
- 设计模式学习笔记——观察者模式
- Java-马士兵设计模式学习笔记-观察者模式-OOD 封装event
- 步步为营 .NET 设计模式学习笔记 十二、Observer (观察者模式)
- java学习笔记-设计模式16(观察者模式)
- 设计模式C++学习笔记之一(Observer观察者模式)
- 设计模式学习笔记--观察者模式
- 《Head First 设计模式》学习笔记之观察者模式
- 【设计模式学习笔记二十】【行为模式】【观察者模式(Observer)】
- 设计模式笔记--观察者模式
- 设计模式笔记-观察者(Observer)
- 设计模式学习笔记(二)之观察者模式(Observer)
- java/android 设计模式学习笔记(2)---观察者模式
- java 设计模式 学习笔记(二)观察者模式
- 设计模式学习笔记-观察者模式