观察者模式解析

1.概述

  观察者模式(Observer Pattern),是软件设计模式中的一种,又称发布-订阅模式,属于发布-订阅架构的一种应用。

  观察者模式定义了对象之间一种一对多的依赖关系。当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。

  比如高温预警系统,政府部门和群众需要知道温度情况,就需要关注温度监测系统,当温度过高时系统向政府和群众发出预警。在这个应用之中,政府部门和群众即是观察者,他们关注的对象温度监测系统是被观察者,当温度状态发生变化时,被观察者向观察者发出通知。

2.结构

  观察者模式的结构如上图所示。

  从图中我们可以看到,观察者模式种包括四个重要角色:

  (1)抽象主题角色(即图中的目标,属于被观察者),它提供一个接口,来负责增加和删除观察者对象。

  (2)具体主题角色(即图中的具体目标),继承自抽象主题角色,它将有关的状态存入具体观察者对象,在其内部状态发生改变时,给所有注册过的观察者发出通知。

  (3)抽象观察者角色:具体观察者的接口。

  (4)具体观察者角色:实现接口,接受主题通知的状态以更新自己的状态使之与主题相协调。

3.推数据与拉数据

  具体主题在通知观察者更新状态时有两种方式:推数据和拉数据。

  推数据:通过参数传递的方式,主题将变化之后的数据全部交给观察者;

  拉数据:主题提供获取数据的方法,当观察者需要时自己去拿取。

推数据方式

拉数据方式

4.观察者模式的优缺点

  优点:

  (1)观察者模式在观察者和被观察者之间建立了一个抽象的耦合。被观察者无需了解任何一个具体观察者,只知道他们之间有一个公共的接口。因此观察者和被观察者可以属于不同的抽象化层次;

  (2)观察者模式支持广播通信,被观察者会向所有注册过的观察者发出通知。

  缺点:

  (1)观察者较多时,通知会花费较长时间;

  (2)如果被观察者之间有循环依赖,会触发他们之间的循环调用导致系统崩溃;

  (3)没有相应的机制使得观察者知道被观察对象是如何变化的。

5.实例

https://github.com/leotoneo/ObserverDesign/blob/master/ObserverDesign.java

  这是一个液位传感器测水位的简单模拟,当水位超过预警线时,传感器通知控制器关闭水阀。

  代码较短,也比较明确,是一个推数据方式的例子,其中传感器为被观察者(主题),控制器为观察者(这一点源码注释中写错了)。

(1)主题类(传感器类)

 1 class Sensor{
 2     //记录当前水位状态
 3     public static int flag = 0;
 4     static ArrayList<Controller> arrayList = new ArrayList<Controller>();
 5     //增加被通知的对象
 6     public void addLisener(Controller controller){
 7         arrayList.add(controller);
 8     }
 9     //传感器工作
10     public static void startWrok(){
11         new Thread(){
12 
13             @Override
14             public void run() {
15                 while(true){
16                     Random random = new Random();
17                     flag = random.nextInt(101);//产生0~100的随机数
18                     if((flag%2)==0){
19                         System.out.println("警告警告 水位超出警戒线");
20                     }else{
21                         System.out.println("现在一切正常");
22                     }
23                     //遍历集合中的每一个控制器,通知他们
24                     for(Controller controller: arrayList){
25                         controller.notificationControner(flag);
26                     }
27                     //休眠1~1.5秒    即1~1.5秒 更新一个状态
28                     Random randomTime = new Random();
29                     int time = randomTime.nextInt(501) + 1000;
30                     try {
31                         Thread.sleep(time);
32                     } catch (InterruptedException e) {
33                         // TODO Auto-generated catch block
34                         e.printStackTrace();
35                     }
36                 }
37             }
38             
39         }.start();
40         
41         
42     }
43 }

 (2)抽象观察者(控制器接口)

1 interface  Controller {
2     public void notificationControner(int flag);
3 }

(3)具体观察者(两个不同的控制器)

 1 //Arm类的控制器(年轻有活力)
 2 class Arm implements Controller{
 3 
 4     @Override
 5     public void notificationControner(int flag) {
 6         if((flag%2)==0){
 7             System.out.println("Arm ,水位超过警戒线了赶紧关闭水阀吧。。。。");
 8         }else{
 9             System.out.println("Arm,玩会游戏吧现在一切正常");
10         }
11         
12         
13     }
14     
15 }
16 //AVR类的控制器(岁数大了 ,反应慢了)
17 class AVR implements Controller{
18 
19     @Override
20     public void notificationControner(int flag) {
21         if((flag%2)==0){
22             System.out.println("AVR,水位过警戒线了,麻烦您老人家给关一下水阀吧!");
23         }else{
24             System.out.println("AVR,赶紧歇会吧,现在一切正常");
25         }
26         
27         
28     }
29     
30 }

参考文章:https://blog.csdn.net/shadow_zed/article/details/75194541

猜你喜欢

转载自www.cnblogs.com/dangolqy/p/9855732.html