Java - GoF设计模式详解20(观察者模式)
二十、观察者模式
1,基本介绍
(1)观察者模式(Observer)又叫做”发布-订阅模式“或者“模型-视图模式”。该模式定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
(2)该模式中包含的角色及其职责如下:
- 抽象主题(Subject):它把所有观察者对象的引用保存在一个集合中,每个主题都可以有任意数量的观察者。抽象主题提供一个接口,可以增加、删除、通知观察者对象。
- 具体主题(Concrete Subject):它实现了抽象主题中定义的抽象方法,在状态发生改变时,会通知所有观察者对象,使它们能够自动更新自己。
- 抽象观察者(Observer):它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。
- 具体观察者(Concrete Observer):它实现了抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。
2,使用样例
(1)下面我们以消息订阅功能作为示例演示观察者模式的使用,即当消息更新时,所有观察者都会收到最新消息。首先我们定义一个抽象主体接口 Subject,该接口定义了注册、删除和通知观察者的方法。
// 抽象主题 interface Subject { // 注册观察者 void registerObserver(Observer o); // 删除观察者 void removeObserver(Observer o); // 通知观察者 void notifyObservers(); }
(2)接着定义一个具体主题 ConcreteSubject 类,改类实现了 Subject 接口,并保存了观察者列表和状态。当状态发生改变时,它会调用 notifyObservers 方法来通知所有观察者。
// 具体主题 class ConcreteSubject implements Subject { // 观察者集合 private List<Observer> observers = new ArrayList<>(); // 当前状态 private String state; // 获取当前状态 public String getState() { return state; } // 修改状态 public void changeState(String state) { this.state = state; // 通知观察者 notifyObservers(); } // 注册观察者 @Override public void registerObserver(Observer o) { observers.add(o); } // 删除观察者 @Override public void removeObserver(Observer o) { observers.remove(o); } // 通知观察者 @Override public void notifyObservers() { for (Observer o : observers) { o.update(this.state); } } }
(3)然后定义一个抽象观察者 Observer 接口,该接口定义了一个更新自身的方法。
// 抽象观察者 interface Observer { // 更新自身方法 void update(String state); }
(4)接着定义具体观察者 ConcreteObserver 类,该类实现了 Observer 接口,并在 update 方法中实现了对主题状态的处理逻辑。
// 具体观察者 public class ConcreteObserver implements Observer { // 观察者名字 private String name; public ConcreteObserver(String name){ this.name = name; } // 更新自身方法 @Override public void update(String state) { System.out.println(this.name + "收到消息:" + state); } }
(5)最后我们创建 1 个主题,2 个观察者对象测试一下:
public class Test { public static void main(String[] args) { // 定义1个主题 ConcreteSubject subject = new ConcreteSubject(); // 定义2个观察者 Observer observer1 = new ConcreteObserver("用户1"); Observer observer2 = new ConcreteObserver("用户2"); // 注册2个观察者 subject.registerObserver(observer1); subject.registerObserver(observer2); // 更新主题状态 subject.changeState("Welcome to hangge.com"); // 删除1个观察者 subject.removeObserver(observer1); // 再次更新主题状态 subject.changeState("欢迎访问 hangge.com"); } }
附一:JDK 中的观察者模式
1,使用 Observable 类和 Observer 接口实现观察者模式
我们可以使用 JDK 中的 java.util.Observable 类和 java.util.Observer 接口实现了观察者模式。更详细的介绍可以参考我之前写的文章:
2,使用 EventListener 接口实现观察者模式
JDK 中的 java.util.EventListener 是一个标记接口,用于定义事件侦听器类。它常用于观察者模式的实现。更详细的介绍可以参考我之前写的文章:
3,javax.swing 中的观察者模式
(1)在 javax.swing 库中,观察者模式通常用于处理 GUI 事件。比如我们可以使用观察者模式来监听按钮的单击事件,或者监听文本框的内容改变事件。下面是一些常见的使用场景:
- JButton 类使用观察者模式来处理按钮单击事件。我们可以通过注册 ActionListener 来监听按钮单击事件,然后在 ActionListener 的 actionPerformed 方法中编写相应的代码。
- JTextField 类使用观察者模式来处理文本框内容改变事件。我们可以通过注册 DocumentListener 来监听文本框内容改变事件,然后在 DocumentListener 的方法中编写相应的代码。
- JComboBox 类使用观察者模式来处理下拉列表选项改变事件。我们可以通过注册 ItemListener 来监听下拉列表选项改变事件,然后在 ItemListener 的 itemStateChanged 方法中编写相应的代码。
(2)下面示例中我们创建了一个按钮和一个文本框,并通过注册 ActionListener 来监听按钮单击事件。当用户点击按钮时,监听器中的 actionPerformed 方法将会被调用,并在文本框中输出信息。
public class Test { public static void main(String[] args) { // 创建一个窗口 JFrame frame = new JFrame("My Window"); frame.setLayout(new BorderLayout()); frame.setSize(400, 300); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 创建一个文本字段 JTextField textField = new JTextField(); frame.add(textField, BorderLayout.CENTER); // 创建一个按钮(被观察者) JButton button = new JButton("点击按钮"); frame.add(button,BorderLayout.NORTH); // 创建按钮监听器(观察者) ActionListener buttonListener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { textField.setText("按钮被点击!"); } }; // 将观察者 (按钮监听器) 注册到被观察者 (按钮) 上 button.addActionListener(buttonListener); // 显示窗口 frame.setVisible(true); } }
附二:Spring 中的观察者模式
1,Spring 事件机制
(1)Spring 事件机制使用观察者模式来传递事件和消息。我们可以使用 ApplicationEvent 类来发布事件,然后使用 ApplicationListener 接口来监听事件。当事件发生时,所有注册的 ApplicationListener 都会得到通知。
(2)关于事件机制更详细的介绍可以参考我之前写的文章:
2,Spring Web MVC
(1)Spring Web MVC 使用观察者模式来处理 HTTP 请求和响应。我们可以使用 DispatcherServlet 来接收 HTTP 请求,然后使用观察者模式来分发请求给处理器(例如 Controller 接口)。当处理器完成请求处理后,DispatcherServlet 再将响应发送回客户端。
(2)具体流程如下:
- 当 DispatcherServlet 接收到一个请求时,它会使用配置的处理器映射器(如 DefaultAnnotationHandlerMapping)来查找匹配的处理器。比如: HelloController 类上有 @RequestMapping 注解,因此 DispatcherServlet 会将请求映射到 HelloController 类的 handleRequest 方法。
- 接着,DispatcherServlet 会使用配置的处理器适配器(如 AnnotationMethodHandlerAdapter)来调用处理器的方法。比如:它会调用 HelloController 类的 handleRequest 方法。
- 处理器方法执行完后,会返回一个 ModelAndView 对象,其中包含了视图名称和模型数据。DispatcherServlet 会使用视图解析器来将视图名称解析为实际的视图,然后将模型数据填充到视图中,最后将视图呈现给客户端。