本篇的设计模式是基于框架去学习,所以顺序不分先后,挑自己需要的学习即可,还在持续更新,感兴趣可以关注一下后续。
监视器模式也称为观察者或发布/订阅模式。
定义了一种一对多的依赖关系,让多个观察者对象同时监听一个主题对象,当主题对象状态发生变化时,会通知所有的观察者对象,使它们自动更新自己。
基本概念包括以下几个方面:
1.主题(Subject):也成称为观察者模式(Observable),它是一个抽象类或接口,用于定义被观察者的基本属性和方法。主题对象包含一组观察者对象的引用,可以在状态发生变化时通知所有观察者对象。
2.观察者(Obserber):订阅者(Subscriber),它是一个抽象类或接口,用于定义观察者对象的基本属性和方法。观察者对象在被主题对象注册后,可以接受主题对象发出的通知,并进行相应的操作。
3.具体主题(Concrete Subject):实现主题或抽象类,它包含一个观察者对象的集合,提供注册,删除,通知等操作,当主题对象状态发生变化时,会通知所有观察者对象。
4.具体观察者(Concrete Observer):实现观察者接口或抽象类,它存储一个指向具体主题对象的引用,在接受到主题对象的通知后,执行相应的操作,使自身状态与主题对象保持同步。
5.通知(Notification):主题对象状态发生变化时,通过调用观察者对象的通知方法来通知观察者对象。
6.订阅(Subscription):观察者对象通过注册方法向主题对象注册,将自身添加到主题对象的观察者列表中。
7.取消订阅(Unsubscription):观察者对象通过删除方法从主题对象的观察者列表中删除自身。
适用场景:
1.一个对象改变需要同时改变其他对象的时候。
业务场景:在一个电商网站中,当用户下单购买商品后,需要通知库存管
2.一个对象的改变会触发连锁反应的时候。
业务场景:游戏中,当玩家升级时,需要通知任务系统判断是否完成了某些任务、通知好友系统向好友发送升级通知等。
3.一个对象需要将自身的状态通知给其他对象的时候。
业务场景:在一个股票交易系统中,当股票价格变化时,需要通知投资者进行交易操作。
4.一个对象需要在不同时间通知不同对象的时候。
业务场景:在一个消息推送系统中,需要根据不同的订阅主题向不同的用户推送消息。
总而言之:监视器模式适用于当多个对象之间的状态存在依赖关系,需要实现一对多的消息通知机制时。
1.使用Java内置的观察者(Observer)接口和可观察者(Observable)类实现。
Observer接口表示观察者,Observable类表示被观察者。
被观察者状态发生变化时,通过调用被观察者类的notifyObservers()方法来通知所有的观察者对象。
这种方式实现了一个标准吧的监视器模式,但要注意:Java中的Observable类是一个类而不是接口,所以不能直接继承它,需要通过继承Observable类的子类来实现。
举个例子来看:
import java.util.Observable;
import java.util.Observer;
// 定义一个被观察者类
class WeatherData extends Observable {
private float temperature;
private float humidity;
private float pressure;
public void measurementsChanged() {
setChanged(); // 标记状态已经改变
notifyObservers(); // 通知所有观察者
}
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged(); // 触发状态改变事件
}
public float getTemperature() {
return temperature;
}
public float getHumidity() {
return humidity;
}
public float getPressure() {
return pressure;
}
}
// 定义一个观察者接口
interface Observer {
void update(Observable observable, Object arg);
}
// 定义一个具体观察者类
class CurrentConditionsDisplay implements Observer {
private float temperature;
private float humidity;
public void update(Observable observable, Object arg) {
if (observable instanceof WeatherData) {
WeatherData weatherData = (WeatherData) observable;
this.temperature = weatherData.getTemperature();
this.humidity = weatherData.getHumidity();
display();
}
}
public void display() {
System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity");
}
}
// 测试代码
public class Test {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay();
weatherData.addObserver(currentDisplay); // 添加观察者
weatherData.setMeasurements(80, 65, 30.4f);
}
}
WeatherData类表示被观察者,CurrentConditionsDisplay类表示观察者。
当WeatherData对象的状态发生改变时,会通过调用Observable类的setChanged()方法来标记状态已经改变,然后通过调用notifyObservers()方法来通知所有的观察者对象。当观察者对象收到通知后,会调用update()方法来更新自身状态。
2.自己实现观察者和被观察者接口。
定义一个抽象的主题(Subject)类和抽象的观察者(Observer)类,具体主题和观察者则通过继承抽象类来实现。
当主题对象状态发生变化时,通知所有观察者对象,并调用观察者对象的更新方法(update())。
举个例子来看:
import java.util.ArrayList;
import java.util.List;
// 观察者接口
interface Observer {
void update(int value);
}
// 被观察者接口
interface Observable {
void addObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObservers();
}
// 被观察者的实现
class MyObservable implements Observable {
private List<Observer> observers = new ArrayList<>();
private int value = 0;
@Override
public void addObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(value);
}
}
// 设置值,并通知所有观察者
public void setValue(int value) {
this.value = value;
notifyObservers();
}
}
// 观察者的实现
class MyObserver implements Observer {
@Override
public void update(int value) {
System.out.println("Value is updated to " + value);
}
}
// 测试代码
public class Main {
public static void main(String[] args) {
MyObservable observable = new MyObservable();
MyObserver observer = new MyObserver();
observable.addObserver(observer); // 添加观察者
observable.setValue(10); // 修改值,并通知观察者
observable.setValue(20); // 修改值,并通知观察者
observable.removeObserver(observer); // 移除观察者
observable.setValue(30); // 修改值,但不通知观察者
}
}
我们自己定义了 Observer 和 Observable 接口,分别表示观察者和被观察者。
3.使用Java内置的事件(Event)类实现。
事件类(Event)是一个基类,可以定义多个派生类,用于表示不同的事件。
事件源(Event Source)负责产生事件,并且在事件发生时通知所有的事件监听器(Event Listener)。
事件监听器(Event Listener)则负责处理事件,并且可以将处理结果通知给事件源或其他对象。
举个例子来看:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
// 观察者类
class MyObserver implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Button is clicked");
}
}
// 测试代码
public class Main {
public static void main(String[] args) {
JFrame frame = new JFrame();
JButton button = new JButton("Click me");
button.addActionListener(new MyObserver()); // 添加观察者
frame.add(button);
frame.pack();
frame.setVisible(true);
}
}
我们使用了 Java 内置的 ActionListener 接口作为观察者接口,JButton 类作为被观察者。
MyObserver 类实现了 ActionListener 接口,在按钮被点击时会触发 actionPerformed 方法。
在 Main 类中,我们创建了一个窗口和一个按钮,将 MyObserver 对象作为按钮的监听器,当按钮被点击时就会通知观察者并执行相应的操作。
4.使用回调函数(Callback)实现。
定义观察者接口和被观察者类,观察者需要实现观察者接口中的方法,并将自己的方法作为参数传递给被观察者。
当被观察者发生变化时,会调用观察者的方法,执行相应的操作。
举个例子来看:
// 观察者接口
interface Observer {
void onUpdate(String message);
}
// 被观察者类
class Observable {
private Observer observer;
// 设置观察者对象
public void setObserver(Observer observer) {
this.observer = observer;
}
// 模拟事件发生,通知观察者
public void eventHappened() {
if (observer != null) {
observer.onUpdate("Event happened");
}
}
}
// 测试代码
public class Main {
public static void main(String[] args) {
Observable observable = new Observable();
// 使用Lambda表达式作为回调函数,实现Observer接口
Observer observer = (message) -> {
System.out.println("Received message: " + message);
};
// 设置观察者对象
observable.setObserver(observer);
// 模拟事件发生
observable.eventHappened();
}
}
定义了一个观察者接口 Observer,它包含一个 onUpdate 方法,表示观察者在接收到通知后需要执行的操作。
被观察者类 Observable 中包含一个 Observer 类型的成员变量 observer,它表示观察者对象。
Observable 类中的 eventHappened 方法模拟一个事件的发生,当事件发生时,被观察者会通知观察者执行相应的操作。
测试代码中,我们使用 Lambda 表达式作为回调函数,实现了 Observer 接口,并将它作为参数传递给 Observable 对象的 setObserver 方法。
当事件发生时,观察者对象就会收到通知,并执行相应的操作。
这个等我更新完refresh后再来填坑。
目前三个常见的适用场景:
1.Spring事件驱动模型:
Spring框架使用了事件(Event)和监听器(Listener)的机制,实现了一种事件驱动的模型。Spring中的事件(Event)通常是一个POJO(Plain Old Java Object)对象,而监听器(Listener)是一个实现了特定接口的POJO对象。当事件被触发时,Spring会通知所有注册了相应监听器的对象,让它们执行相应的操作。
2.Spring AOP(面向切面编程):
Spring AOP中的切面就是一个特殊的监听器,它可以监听被通知对象(即目标对象)的方法调用,并在相应的时机执行一些操作。
3.Spring MVC(模型-视图-控制器):
Spring MVC中的控制器(Controller)通常是一个Servlet或者一个POJO,它可以接收HTTP请求并处理相应的业务逻辑。当一个请求被发送到控制器时,Spring会触发一个事件,并通知所有注册了相应监听器的对象。这些监听器可以对请求进行一些预处理或者后处理,比如记录请求日志、检查权限等。
后面我们更深入的去赏析监听器模式给spring带来的帮助。