项目介绍:高温预警系统旨在气象部门根据气象卫星获得相关的天气温度信息,当温度超过某一阈值时,向各个单位和个人发出高温警报通知,以及时做好高温防护措施。这是一个典型的观察者模式使用场景。
项目代码链接:
https://github.com/hj841104031/MyJavaProject
系统结构图如下图所示:
模式分析:
高温预警过程分析
1.想要得到温度信息,这需要气温关注者 “订阅”高温预警服务。
Observer的接口定义如下:
package Observer; public interface Observer { public void update(Subject subject); }
Person类对Observer的具体实现如下:
package Observer; public class Person implements Observer { public Person(Subject subject) { subject.add(this); } public void update(Subject subject) { System.out.println("个人收到高温预警:" + subject.temperatureReport()); } }
观察者接口定义了update的方法,当有温度信息时接收温度信息。程序代码中包含有三个观察者,分别是Person、Company与Government。这三个具体的观察者分别对update函数进行了相应的重写。
总的来说观察者模式在被观察者和观察者之间建立一个抽象的耦合。被观察者角色所知道的只是一个具体现察者聚集,每一个具体观察者都符合一个抽象观察者的接口。被观察者并不认识任何一个具体观察者,它只知道它们都有一个共同的接口。
2.高温预警系统需要知道哪些对象是需要通知的。这需要预警系统维护一个关注者列表。
3.高温预警系统在温度达到阈值的时候,通知所有“订阅”服务的关注者。如何通知呢?这需要气温关注者具备接收通知的功能。
为了实现以上两个功能需要将Subject接口的定义如下:
package Observer; public interface Subject { // 增加观察者 public boolean add(Observer observer); // 删除观察者 public boolean remove(Observer observer); // 通知所有观察者更新数据 public void notifyAllObserver(); // 设置温度值 public void setTemperature(float temperature); // 获得温度预警 public String temperatureReport(); }
这个抽象主题类实现了以下的功能:
- 增加观察者
- 删除观察者
- 通知所有观察者更新数据
- 设置温度值
- 获得温度预警
以及对Subject接口的具体实现类ForcastSystem的代码如下:
package Observer; import java.util.Iterator; import java.util.Vector; public class ForcastSystem implements Subject { private float temperature; // 温度 private String warningLevel; // 预警级别 private final Vector<Observer> vector; // 观察者列表 // 构造方法 初始化观察者列表 public ForcastSystem() { vector = new Vector<Observer>(); } // 增加观察者 public boolean add(Observer observer) { if (observer != null && !vector.contains(observer)) { return vector.add(observer); } return false; } // 移除观察者 public boolean remove(Observer observer) { return vector.remove(observer); } // 通知所有观察者更新数据 public void notifyAllObserver() { System.out.println("======气象部门发布高温" + this.warningLevel + "警报!======"); Iterator<Observer> iterator = vector.iterator(); while (iterator.hasNext()) { (iterator.next()).update(this); } } // 私有方法 根据温度值设置预警级别 然后通知所有观察者 private void invoke() { if (this.temperature >= 35) { if (this.temperature >= 35 && this.temperature < 37) { this.warningLevel = "黄色"; } else if (this.temperature >= 37 && this.temperature < 40) { this.warningLevel = "橙色"; } else if (this.temperature >= 40) { this.warningLevel = "红色"; } // 通知所有观察者温度状况 this.notifyAllObserver(); } } // 设置温度值 public void setTemperature(float temperature) { this.temperature = temperature; this.invoke(); } // 获得温度预警 public String temperatureReport() { return " 温度:" + this.temperature; }
public void notifyAllObserver()这个函数调用了iterator迭代器来判断是否有数据信息的更新操作,如果有新的数据被更新,则向所有的观察者发送最新的温度消息。
总的来看 高温预警系统和气温关注者,两者关系如下图所式:
静态建模
进一步将整个系统抽象,形成的静态关系结构如下图所示。
观察者模式的优点
- 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面。在我们的这个网络监控中,观察者依赖于被观察者。
- 当对一个对象的改变需要同时改变其它对象,而不知道具体有多少个对象待改变。当被观察者的数据要发生改变时,对应的观察者的数据也要改变,这个时候只要将被观察者里的观察者集合都改变了就可以了
- 当一个对象必须通知其它对象,而它又不能假定其它对象是谁。换句话说,你不希望这些对象是紧密耦合的。
- 在观察者和被观察者之间建立了一个耦合,对于被观察者来说,他只对它的观察者集合负责,然后具体的网络改变都是通过接口传递,只需要改变setTempearture()与notifyAllObserver()即可,剩下的不需要被观察者在意。被观察者也不需要知道观察者都有些谁。
- 而对于观察者而言,它不需要知道被观察者的情况,只需要知道接口传下来的netaciton(具体动作如网络状态、WiFi改变),执行自己的update()更新自己的状态即可。
- 它们没有紧密的耦合,可以属于不同的抽象化层次
- 一旦数据改变,支持广播通信很适合被观察者向每一个观察者广播改变网络状态的通知。