当前位置: > > > Java - GoF设计模式详解20(观察者模式)

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 来监听按钮单击事件,然后在 ActionListeneractionPerformed 方法中编写相应的代码。
  • JTextField 类使用观察者模式来处理文本框内容改变事件。我们可以通过注册 DocumentListener 来监听文本框内容改变事件,然后在 DocumentListener 的方法中编写相应的代码。
  • JComboBox 类使用观察者模式来处理下拉列表选项改变事件。我们可以通过注册 ItemListener 来监听下拉列表选项改变事件,然后在 ItemListeneritemStateChanged 方法中编写相应的代码。

(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 会使用视图解析器来将视图名称解析为实际的视图,然后将模型数据填充到视图中,最后将视图呈现给客户端。
评论0