文章内容
一、什么是观察者模式
观察者模式,定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。
观察者模式,也叫发布-订阅模式、模型-视图模式,属于行为型结构模式。
二、观察者模式类图
三、观察者模式角色
- 抽象主题角色(Subject): 也叫抽象被观察者,是把所有观察者对象保存到一个集合里,抽象主题提供一个接口,包含增加和删除观察者对象,以及通知所有观察者的抽象方法。
- 具体主题角色(ConcreteSubject):也叫具体被观察者,实现抽象主题接口中的通知方法,将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有注册过的观察者发送通知。
- 抽象观察者角色(Observer):观察者的抽象类,是一个抽象类或接口,包含了更新自己的抽象方法,使得在得到主题更改通知时被调用。
- 具体观察者角色(ConcreteObserver):具体观察者类,实现抽象观察者定义的更新接口,以便在得到主题更改通知时更新自身的状态。
四、观察者模式优缺点
1、优点
- 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系,满足依赖倒置原则。
- 被观察者发送通知,所有注册的观察者都会收到信息(类似于消息广播机制)。
2、缺点
- 如果观察者非常多的话,所有的观察者收到被观察者发送的通知会比较耗时,影响性能。
- 如果被观察者有循环依赖的话,有可能出现循环调用,导致系统崩溃。
五、观察者模式Demo示例
1、Demo需求
门户网站天气预报:新浪网站、网易网站、搜狐网站都有天气数据(温度、湿度、气压),在天气变化时通知各门户网站进行更新天气数据。
2、数据类定义
/**
* 天气数据类
*/ public class WeatherInfo {
//溫度
private String temperature;
//气压
private String pressure;
//湿度
private String humidity;
public WeatherInfo(String temperature, String pressure, String humidity) {
this.temperature = temperature;
this.pressure = pressure;
this.humidity = humidity;
}
@Override
public String toString() {
return "WeatherInfo{" +
"temperature='" + temperature + ''' +
", pressure='" + pressure + ''' +
", humidity='" + humidity + ''' +
'}';
}
}
3、接口定义
/**
* 抽象观察者角色:天气预报抽象观察者类
*/ public interface Observer {
void update(WeatherInfo weatherInfo);
}
/**
* 抽象主题角色:被观察者类
*
*/ public abstract class Subject {
// 用于存放观察者对象的集合
protected List<Observer> observers = new ArrayList<>();
/**
* 添加观察者到集合中
* @param observer
*/ public void add(Observer observer){
observers.add(observer);
}
/**
* 从集合中删除观察者
* @param observer
*/ public void remove(Observer observer){
observers.remove(observer);
}
/**
* 天气变化时,通知所有观察者
* 由子类实现
* @param weatherInfo
*/ public abstract void notify(WeatherInfo weatherInfo);
}
4、观察者定义
/**
* 具体观察者角色:新浪观察者类
*/ public class SinaObserver implements Observer {
@Override
public void update(WeatherInfo weatherInfo) {
System.out.println("<<<==新浪门户网站==>>>");
System.out.println(weatherInfo);
System.out.println("<<<==新浪门户网站==>>>");
}
}
/**
* 具体观察者角色:搜狐网站观察者类
*/ public class SohuObserver implements Observer {
@Override
public void update(WeatherInfo weatherInfo) {
System.out.println("<<<==搜狐门户网站==>>>");
System.out.println(weatherInfo);
System.out.println("<<<==搜狐门户网站==>>>");
}
}
/**
* 具体观察者角色:网易网站观察者类
*/ public class WangyiObserver implements Observer {
public void update(WeatherInfo weatherInfo) {
System.out.println("<<<==网易门户网站==>>>");
System.out.println(weatherInfo);
System.out.println("<<<==网易门户网站==>>>");
}
}
5、被观察者定义
/**
* 具体主题角色:天气预报主题类(具体被观察者类)
*/ public class WeatherSubject extends Subject {
private WeatherInfo weatherInfo;
/**
* 通知所有观察者对象
*
* @param weatherInfo
*/ @Override
public void notify(WeatherInfo weatherInfo) {
for (Observer observer : observers) {
observer.update(weatherInfo);
}
}
}
6、测试
/**
* 观察者模式客户端测试类
*
*/ public class Client {
public static void main(String[] args) {
Observer sina = new SinaObserver();
Observer sohu = new SohuObserver();
Observer wangyi = new WangyiObserver();
Subject observable = new WeatherSubject();
observable.add(sina);
observable.add(sohu);
observable.add(wangyi);
observable.notify(new WeatherInfo("36.3","399.09","120.99"));
}
}
<<<==新浪门户网站==>>>
WeatherInfo{temperature='36.3', pressure='399.09', humidity='120.99'}
<<<==新浪门户网站==>>>
<<<==搜狐门户网站==>>>
WeatherInfo{temperature='36.3', pressure='399.09', humidity='120.99'}
<<<==搜狐门户网站==>>>
<<<==网易门户网站==>>>
WeatherInfo{temperature='36.3', pressure='399.09', humidity='120.99'}
<<<==网易门户网站==>>>