观察者模式(Observer Pattern)
观察者模式又称为发布/订阅模式,它是软件设计模式的一种。观察者模式定义了对象间的一种一对多的依赖关系,当一个对象状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。大类划分为行为型模式。
介绍
意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
应用场景:
1. 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面,需要将这两个方面分别封装到独立的对象中,彼此独立地改变和复用的时候。
2. 当一个系统中一个对象的改变需要同时改变其他对象内容,但是不知道待改变的对象到底有多少个的时候;
3. 当一个对象的改变必须通知其他对象作出相应的变化,但是不能确定通知的对象是谁的时候。
角色:
1. 抽象主题角色(Subject):定义被观察者接口,包括注册观察者方法(将观察者添加到集合容器中)、注销观察者方法,以及当发生变化时通知更新观察者方法。
2. 具体主题角色(ConcreteSubject):定义了具体的被观察对象。在其内容含有存储观察者对象实例的集合,用于保存注册的观察者对象。
3. 抽象观察者角色(IObserver):定义观察者通用接口,通常包含一个update接口方法,用于在被观察者发生变化时,调用该方法更新数据。
4. 具体观察者角色(ConcreteObserver):定义具体的观察者对象,实现update更新方法,与具体主题角色状态一致。
优点:观察者和被观察者是抽象耦合的;建立一套触发机制。
缺点:
1. 如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
2. 如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
3. 观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
注意事项:
1. JAVA中已经有了对观察者模式的支持类。
2. 避免循环引用。
3. 如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式。
实现
本例实现中,我们模拟一个天气预报高温预警的场景。有三个观察者(公司,政府,个人),被观察对象(高温预警系统)。高温预警在温度达到指定温度之后,会通知这三个观察者,观察者根据自身逻辑作出响应。本例中,我们要面向抽象编程。
步骤 1
定义被观察者ISubject接口和观察者IObserver接口。
ISubject.java
package com.mrcsj.test.study.observer;
/**
* 被观察者接口(高温预警系统)
* @author admin
* @version 1.0
* @created 23-十一月-2016 14:31:52
*/
public interface ISubject {
/**
*
* @param observer
*/
public boolean add(IObserver observer);
public void notifyAllObserver();
/**
*
* @param observer
*/
public boolean remove(IObserver observer);
/**
* 报告温度
*/
public String reportTemperature();
/**
* 设置温度
*
* @param temperature
*/
public void setTemperature(float temperature);
}
IObserver.java
package com.mrcsj.test.study.observer;
/**
* 观察者接口
* @author admin
* @version 1.0
* @created 23-十一月-2016 14:31:51
*/
public interface IObserver {
/**
*
* @param subject
*/
public void update(ISubject subject);
}
步骤 2
构造具体的被观察者对象和观察者对象。
Subject.java
package com.mrcsj.test.study.observer;
import java.util.Iterator;
import java.util.Vector;
/**
*
* @author admin
* @version 1.0
* @created 23-十一月-2016 14:31:54
*/
public class Subject implements ISubject {
public IObserver m_IObserver;
/**
* (一)高温黄色预警信号
* 标准:连续三天日气温最高位35℃以上。
* (二)高温橙色预警信号
* 标准:24小时之内最高气温将升至37℃以上。
* (三)高温红色预警
* 标准:24小时之内最高气温将升至40℃以上。
*/
private float temperature;
/**
* 预警级别
*/
private String warningLevel;
/**
* 保存观察者列表
*/
private Vector<IObserver> vector;
public Subject(){
vector = new Vector<IObserver>();
}
public void finalize() throws Throwable {
}
/**
*
* @param observer
*/
public boolean add(IObserver observer){
if(null != observer && !vector.contains(observer)) {
return vector.add(observer);
}
return false;
}
public void notifyAllObserver(){
System.out.println("=====气象部门发布高温" +
this.warningLevel + "预警!====");
Iterator<IObserver> iterator = vector.iterator();
while(iterator.hasNext()) {
iterator.next().update(this);
}
}
/**
*
* @param observer
*/
public boolean remove(IObserver observer){
return vector.remove(observer);
}
/**
* 报告温度
*/
public String reportTemperature(){
return "温度:" + this.temperature;
}
/**
* 设置温度
*
* @param temperature
*/
public void setTemperature(float temperature){
this.temperature = temperature;
this.invoke();
}
private void invoke() {
if(this.temperature >= 35) {
if(this.temperature < 37) {
this.warningLevel = "黄色";
}else if (this.temperature >= 37 && this.temperature < 40) {
this.warningLevel = "橙色";
}else if (this.temperature >= 40){
this.warningLevel = "红色";
}
}
this.notifyAllObserver();
}
}//end Subject
PersonalObserver.java
package com.mrcsj.test.study.observer;
/**
* 个人观察者
* @author admin
* @version 1.0
* @created 23-十一月-2016 14:31:53
*/
public class PersonalObserver implements IObserver {
public PersonalObserver(){
}
public void finalize() throws Throwable {
}
/**
*
* @param subject
*/
public void update(ISubject subject){
System.out.println("个人收到高温预警," + subject.reportTemperature());
}
}//end PersonalObserver
CompanyObserver.java
package com.mrcsj.test.study.observer;
/**
* 公司观察者
* @author admin
* @version 1.0
* @created 23-十一月-2016 14:31:48
*/
public class CompanyObserver implements IObserver {
public CompanyObserver(){
}
public void finalize() throws Throwable {
}
/**
*
* @param subject
*/
public void update(ISubject subject){
System.out.println("公司收到高温预警, " + subject.reportTemperature());
}
}//end CompanyObserver
GovernmentObserver.java
package com.mrcsj.test.study.observer;
/**
* 政府观察者
* @author admin
* @version 1.0
* @created 23-十一月-2016 14:31:49
*/
public class GovernmentObserver implements IObserver {
public GovernmentObserver(){
}
public void finalize() throws Throwable {
}
/**
*
* @param subject
*/
public void update(ISubject subject){
System.out.println("政府收到高温预警," + subject.reportTemperature());
}
}//end GovernmentObserver
步骤 3
构造客户端类,进行代码测试。
Client.java
package com.mrcsj.test.study.observer;
/**
* 客户端
* @author admin
* @version 1.0
* @created 23-十一月-2016 14:31:47
*/
public class Client {
public static void main(String[] args) {
IObserver companyObserver = new CompanyObserver();
IObserver personalObserver = new PersonalObserver();
IObserver governmentObserver = new GovernmentObserver();
ISubject subject = new Subject();
subject.add(governmentObserver);
subject.add(personalObserver);
subject.add(companyObserver);
subject.setTemperature(38.5f);
}
}//end Client
步骤 4
验证输出。
=====气象部门发布高温橙色预警!====
政府收到高温预警,温度:38.5
个人收到高温预警,温度:38.5
公司收到高温预警, 温度:38.5