一、定义:
观察者模式中,观察者模式定义了对象之间的一对多依赖关系,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并且自动更新。 在这里,发生改变的对象称之为观察目标,而被通知的对象称之为观察者。一个观察目标可以对应多个观察者,而且这些观察者之间没有相互联系,所以么可以根据需要增加和删除观察者,使得系统更易于扩展。
观察者模式又称为发布-订阅模式。
UML结构图:
该模式包含四个角色:
(1)Subject:抽象主题(被观察者)。他把所有对观察者对戏的引用保存在一个集合里,每一个主题都可以有多个观察者。被观察者提供一个接口,可以增加和删除观察者角色。一般用一个抽象类和接口来实现。
(2)Observer:抽象观察者。为所有的具体观察者定义一个接口,在得到主题的通知时能够及时的更新自己
(3)ConcreteSubject:具体主题。将有关状态存入具体观察者对象。在具体主题发生改变时,给所有的观察者发出通知。
(4)ConcreteObserver:具体观察者。实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态相协调。如果需要,具体观察者角色可以保存一个指向具体主题角色的引用。
二、实现观察者模式:
情景是这样的:在气象观测站中,它能够追踪目前的天气状况,包括温度、适度、气压。需要实现一个布告板,能够分别显示目前的状态,气象统计和简单的预报。当气象站中获取最新的测量数据时,三种布告板必须实时更新。
下面是这个案例的设计图:
编码实现:
主题接口 Subject.java
public interface Subject {
/**
* 注册观察者
* @param observer
*/
public void registerObserver(Observer observer);
/**
* 删除观察者
* @param observer
*/
public void removeOberver(Observer observer);
/**
* 当主题状态发生改变时,这个方法需要被调用,以通知所有观察者
*/
public void notifyObserver();
}
观察者接口 Observer.java
public interface Observer {
public void update(float temp,float humidity,float pressure);
}
布告板显示接口 DisplayElement.java
public interface DisplayElement {
public void display();
}
WeatherData实现主题接口 WeatherData.java
public class WeatherData implements Subject{
private List<Observer> observers;
private float tempterature;
private float pressure;
private float humidity;
public WeatherData(){
observers = new ArrayList<Observer>();
}
@Override
public void notifyObserver() {
for(int i = 0; i < observers.size();i++){
Observer observer = observers.get(i);
observer.update(tempterature, humidity, pressure);
}
}
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeOberver(Observer observer) {
int i = observers.indexOf(observer);
if(i >= 0){
observers.remove(i);
}
}
/**
* 气象站得到更新的观测数据时,通知观察者
*/
public void measurementChanged(){
notifyObserver();
}
public void setMeasurements(float temperature,float humidity,float pressure){
this.tempterature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementChanged();
}
}
布告板 CurrentCondituonDisplay.java
public class CurrentConditionsDisplay implements Observer,DisplayElement{
private float temperature;
private float humidity;
private Subject weatherData;
public CurrentConditionsDisplay(Subject weatherData){
this.weatherData = weatherData;
weatherData.registerObserver(this); //注册观察者
}
public void update(float temp, float humidity, float pressure) {
this.temperature = temp;
this.humidity = humidity;
display();
}
@Override
public void display() {
System.out.println("Current conditions:"+temperature+"F degrees and "+humidity+"% humidity");
}
}
测试程序 WeatherStation
public class WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay conditionsDisplay = new CurrentConditionsDisplay(weatherData);
weatherData.setMeasurements(80, 65, 30.4f);
weatherData.setMeasurements(82, 70, 29.2f);
weatherData.setMeasurements(78, 78, 40.4f);
}
}
运行结果:
三、观察者模式小结:
1、观察者模式的两种模式:
观察者模式在关于目标角色、观察者角色通信的具体实现中,有两个版本:
(1)一种情况便是目标角色在发生变化后,仅仅告诉观察者角色“我变化了”,观察者角色如果想要知道具体的变化细节,则就要自己从目标角色的接口中得到。这种模式被很形象的称为:拉模式——就是说变化的信息是观察者角色主动从目标角中“拉”出来的。
(2)还有一种方法,那就是我目标角色“服务一条龙”,通知你发生变化的同时,通过一个参数将变化的细节传递到观察者角色中去。这就是“推模式”——管你要不要,先给你啦。
这两种模式的使用,取决于系统设计时的需要。如果目标角色比较复杂,并且观察者角色进行更新时必须得到一些具体变化的信息,则“推模式”比较合适。如果目标角色比较简单,则“拉模式”就很合适啦。
2、优点:
(1)当两个对象之间松耦合,他们依然可以交互,但是不太清楚彼此的细节。观察者模式提供了一种对象设计,让主题和观察者之间松耦合。主题所知道只是一个具体的观察者列表,每一个具体观察者都符合一个抽象观察者的接口。主题并不认识任何一个具体的观察者,它只知道他们都有一个共同的接口。
(2)观察者模式支持“广播通信”。主题会向所有的观察者发出通知。
(3)观察者模式符合“开闭原则”的要求。
3、缺点:
(1)如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。
(2)如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。
(3)观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。
4、适用场所:
(1)一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将二者封装在独立的对象中使它们可以各自独立地改变和复用。
(2)一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
(3)一个对象必须通知其他对象,而并不知道这些对象是谁。需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。换言之, 你不希望这些对象是紧密耦合的。
原博客链接:
https://blog.csdn.net/chenssy/article/details/8955696
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/100068.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...