1. 观察者模式简介
1.1. 什么是观察者模式
观察者模式是一种行为型设计模式,用于建立对象之间的一对多依赖关系。在该模式中,一个被称为主题(Subject)的对象维护一组观察者(Observer),并在其状态发生变化时自动通知观察者。这样,观察者对象可以及时获取主题对象的最新状态并执行相应的操作。
1.2. 观察者模式涉及的角色
主题(Subject):被观察的对象,维护一组观察者并提供注册、删除和通知观察者的方法。
观察者(Observer):接收主题通知的对象,定义了一个更新方法,在接收到通知时执行相应的操作。
具体主题(Concrete Subject):具体的主题实现类,继承或实现主题接口,并在状态变化时通知观察者。
具体观察者(Concrete Observer):具体的观察者实现类,实现观察者接口,并在收到通知时执行具体的操作。
1.3. 观察者模式的工作原理
主题对象维护一个观察者列表,该列表存储了所有订阅主题通知的观察者对象。当主题对象的状态发生变化时,它会遍历观察者列表,并调用每个观察者对象的更新方法,将新的状态传递给观察者。观察者对象接收到主题的通知后,执行相应的操作,以便响应状态的变化。
1.4. 观察者模式的优点
解耦性:主题和观察者之间是松耦合的,它们之间通过抽象的接口进行通信,使得它们可以独立地进行修改和扩展。
可扩展性:可以方便地增加新的观察者,而无需修改主题的代码。
随时更新:主题状态变化时,观察者能够立即得到通知并进行相应的操作。
规范性:观察者模式定义了主题和观察者之间的一套规范,使得代码更具可读性和可维护性。
2. 代码实现
代码实现最好自己手写一遍,有利于更加理解观察者模式:
2.1.主题接口 Subject
首先,定义一个主题接口 Subject
,其中包含三个方法:registerObserver()
用于注册观察者,removeObserver()
用于移除观察者,notifyObservers()
用于通知观察者:
package DesignPattern.observerMode;
/**
* @Author: stukk
* @Description: 主题接口
* @DateTime: 2023-12-13 22:13
**/
public interface Subject {
void registerObServer(Observer obServer);
void removeObServer(Observer obServer);
void notifyObServer();
}
2.2. 具体主题类 ConcreteSubject
然后,实现一个具体主题类 ConcreteSubject
,它维护一个观察者列表,并在状态变化时通知观察者。
package DesignPattern.observerMode.Impl;
import DesignPattern.observerMode.Observer;
import DesignPattern.observerMode.Subject;
import java.util.LinkedList;
import java.util.List;
/**
* @Author: stukk
* @Description: 主题接口实现类
* @DateTime: 2023-12-13 22:14
**/
public class ConcreteSubject implements Subject {
private List<Observer> obServers = new LinkedList<>(); //存储观察者
private int state; //观察对象
public void setState(int state) {
this.state = state;
notifyObServer();
}
@Override
public void registerObServer(Observer obServer) {
obServers.add(obServer);
}
@Override
public void removeObServer(Observer obServer) {
obServers.remove(obServer);
}
@Override
public void notifyObServer() { //通知观察者们
obServers.forEach(obServer -> {
obServer.update(state);
});
}
}
2.3. 观察者接口 ObServer
接下来,定义一个观察者接口 ObServer
,其中包含一个 update()
方法,用于接收和处理主题的通知。
package DesignPattern.observerMode;
/**
* @Author: stukk
* @Description: 观察者接口
* @DateTime: 2023-12-13 22:11
**/
public interface Observer {
void update(int state);
}
2.4. 具体观察者类ConcreteObServer
实现一个具体观察者类 ConcreteObServer
,它实现了 Observer
接口,并在收到通知时输出状态信息。
package DesignPattern.observerMode.Impl;
import DesignPattern.observerMode.Observer;
/**
* @Author: stukk
* @Description: 观察者接口实现类
* @DateTime: 2023-12-13 22:12
**/
public class ConcreteObserver implements Observer {
private String name; //观察者的名字
public ConcreteObserver(String name) {
this.name = name;
}
@Override
public void update(int state) {
System.out.println(name + "接收到了更新请求,新的状态:" +state );
}
}
2.5. 测试观察者模式
最后我们写一个类来测试观察者的功能
package DesignPattern.observerMode;
import DesignPattern.observerMode.Impl.ConcreteObserver;
import DesignPattern.observerMode.Impl.ConcreteSubject;
/**
* @Author: stukk
* @Description: 测试观察者模式
* @DateTime: 2023-12-13 22:24
**/
public class ObserverModeExample {
public static void main(String[] args) {
// 主题
ConcreteSubject subject = new ConcreteSubject();
Observer obServer1 = new ConcreteObserver("观察者1号");
Observer obServer2 = new ConcreteObserver("观察者2号");
Observer obServer3 = new ConcreteObserver("观察者3号");
// 注册观察者
subject.registerObServer(obServer1);
subject.registerObServer(obServer2);
subject.registerObServer(obServer3);
subject.setState(1);
// 删除2再试试
subject.removeObServer(obServer2);
subject.setState(2);
}
}
最后输出:
3. 观察者模式的应用场景
-
当一个对象的状态变化需要通知其他多个对象,并且这些对象的更新行为可能不同的时候:例如,当一个订单状态发生变化时,需要通知多个观察者,如库存管理系统、物流系统和消息通知系统等。
-
当存在一对多的依赖关系,一个对象的变化会引起其他多个对象的变化的时候:例如,当一个博客发表新文章时,订阅该博客的多个读者都会收到通知并更新自己的阅读列表。
-
当需要将关注点分离,使得主题和观察者之间解耦的时候:主题只需要知道观察者接口,而不需要了解具体的观察者实现。这样可以提高代码的灵活性和可扩展性。
-
当系统需要动态地将观察者添加到或移除出主题中的时候:通过动态注册和移除观察者,可以在运行时灵活地管理观察者集合。