观察者模式是一种对象行为模式。它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。所以又被称为发布-订阅模式(Publish/Subscribe)。
使用场景:
1、当一个抽象模型有两个方面,其中一个方面依赖于另一方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
2、当对一个对象的改变需要同时改变其他对象,而不知道具体有多少对象需要被改变。
3、当一个对象必须通知其他对象,而它又不能假定其他对象是谁。换言之,不希望这些对象是紧密耦合的。
1、抽象主题(Subject):
它把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
2、具体主题(Concrete Subject):
将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。
3、抽象观察者(Observer):
为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
4、具体观察者(Concrete Observer):
实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。
优缺点:
观察者模式的主要的作用就是对对象解耦,将观察者和被观察者完全隔离。
1、观察者模式的优点
观察者模式解除了主题和具体观察者的耦合,让耦合的双方都依赖于抽象,而不是依赖具体。
2、观察者模式的缺点
在应用观察者模式时需要考虑一下开发小路问题,程序中包括一个被观察者和多个被观察者,开发和调试比较复杂,而且Java中的消息的通知默认是顺序执行的,一个观察者的卡顿会影响整体的执行效率。在这种情况下,一般考虑采用异步的方式。
场景:
- 手机丢了,委托别人给其他人发消息通知
- 拍卖,拍卖师观察最高标价,然后通知给其它竞价者竞价
- 在一个目录下建立一个文件,会同时通知目录管理器增加目录,并通知磁盘减少空间,文件是被观察者,目录管理器和磁盘管理器是观察者
- 猫叫了一声,吓着了老鼠,也惊到了主人,猫是被观察者,老鼠和人是观察者。
案例:天气提供者,天气变化通知第三方。
public interface Subject {
public void registerObserver(Observer observer);
public void removeObserver(Observer observer);
public void notifyObserver();
}
public interface Observer {
/**
* 更新数据
* @param temperature
* @param pressure
* @param humidity
*/
public void update(float temperature,float pressure,float humidity);
}
public class CurrrentConditions implements Observer{
@Override
public void update(float temperature, float pressure, float humidity) {
System.out.printf("温度:"+temperature);
System.out.printf("气压:"+pressure);
System.out.printf("湿度:"+humidity);
}
}
import java.util.ArrayList;
import java.util.List;
public class WeatherData implements Subject {
private float temperature;
private float pressure;
private float humidity;
//观察者集合
private List<Observer> list = new ArrayList<>();
public WeatherData() {
}
public float getTemperature() {
return temperature;
}
public void setTemperature(float temperature) {
this.temperature = temperature;
}
public float getPressure() {
return pressure;
}
public void setPressure(float pressure) {
this.pressure = pressure;
}
public float getHumidity() {
return humidity;
}
public void setHumidity(float humidity) {
this.humidity = humidity;
}
public void updateOrSaveData(float temperature,float pressure,float humidity){
this.temperature=temperature;
this.pressure=pressure;
this.humidity=humidity;
notifyObserver();
}
public List<Observer> getList() {
return list;
}
public void setList(List<Observer> list) {
this.list = list;
}
@Override
public void registerObserver(Observer observer) {
list.add(observer);
}
@Override
public void removeObserver(Observer observer) {
list.remove(observer);
}
/**
* 通知
*/
@Override
public void notifyObserver() {
list.stream().forEach(observer -> {
observer.update(this.temperature,this.pressure,this.humidity);
});
}
}
public class Client {
public static void main(String[] args) {
//被观察者
WeatherData weatherData=new WeatherData();
//观察者
CurrrentConditions currrentConditions=new CurrrentConditions();
//注册观察者
weatherData.registerObserver(currrentConditions);
//更新数据
weatherData.updateOrSaveData(10f,120f,30.3f);
}
}