Observable 设计模式简介

Observable 设计模式用于许多重要的 Java API。 一个著名的例子是一个 JButton,它使用 ActionListener 执行操作的 API。 在这个例子中,我们有一个 ActionListener 听或观察按钮。 单击该按钮时, ActionListener 执行一个动作。

Observable 模式也用于响应式编程。 在反应式应用程序中使用观察者是有道理的,因为反应式的本质是反应:当另一个进程发生时,事情就会发生。

Observable 是一种行为设计模式。 它的功能是在事件发生时执行一个动作。 两个常见的例子是按钮点击和通知,但这种模式还有更多用途。

Observable 模式的一个例子

在 Observable 模式中,一个对象在执行操作时通知另一个对象。 为了理解该模式的价值,让我们想象一个需要单击按钮并且没有通知另一个对象的场景,如图 1 所示。

国际数据集团

图 1. ActionCheck 每秒检查一次按钮。

请注意, ActionCheck 必须每秒检查一次按钮。 现在,想象一下,如果我们每秒对该按钮进行多次操作检查。 您能想象这会对您的应用程序性能产生什么影响吗?

让 Do Something 按钮通知 ActionCheck. 这样, ActionCheck 逻辑不需要每秒轮询 Do Something 按钮。

Observable设计模式的元素

在下图中,请注意观察者模式的基础是 Observer 接口(即观察的对象)和 Subject (被观察的对象)。 这 Newsletter 班级工具 SubjectSubscriber 工具 Observer. 然后,最后, SendEmailMain 执行 Observable 设计模式。

国际数据集团

图 2. 订阅者示例中 Observable 设计模式的流程。

代码中的 Observable 模式

Subject 接口,也称为 Observable 或者 Publisher, 是 Observable 设计模式的基础。 基本上,它存储观察者并在观察到的动作发生时立即通知他们。 看看 Subject 界面。


public interface Subject {

    void addSubscriber(Observer observer);
    void removeSubscriber(Observer observer);
    void notifySubscribers();

}

观察者界面

Observer 接口(有时也称为 Subscriber) 由订阅者实现,它试图观察是否执行了一个动作:


public interface Observer {

    public void update(String email);

}

行动中可观察

让我们用一个时事通讯的例子来实现 Subject 界面。 在下面的代码中,我们存储我们的观察者(在本例中为时事通讯订阅者),并且当他们的电子邮件被添加到订阅时,每个订阅者都会收到通知。


import java.util.ArrayList;
import java.util.List;

public class Newsletter implements Subject {

    protected List<Observer> observers = new ArrayList<>();
    protected String name;
    protected String newEmail;

    public Newsletter(String name) {
        this.name = name;
    }

    public void addNewEmail(String newEmail) {
        this.newEmail = newEmail;
        notifySubscribers();
    }

    @Override
    public void addSubscriber(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeSubscriber(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifySubscribers() {
        observers.forEach(observer -> observer.update(newEmail));
    }
}

订户

Subscriber 类代表订阅电子邮件通讯的用户。 这个类实现了 Observer 界面。 它是我们将观察的对象,以便我们知道事件是否发生。


class Subscriber implements Observer {

  private String name;

  public Subscriber(String name) {
    this.name = name;
  }

  @Override
  public void update(String newEmail) {
    System.out.println("Email for: " + name + " | Content:" + newEmail);
  }

}

发送邮件主

现在我们有了使 Observable 模式有效工作的主类。 首先,我们将创建 Newsletter 目的。 然后,我们将添加和删除订阅者。 最后,我们将添加一封电子邮件并通知订阅者他们的状态。


public class SendEmailMain {

  public static void main(String[] args) {
    Newsletter newsLetter = new Newsletter("Java Challengers");

    Observer duke = new Subscriber("Duke");
    Observer juggy = new Subscriber("Juggy");
    Observer dock = new Subscriber("Moby Dock");

    newsLetter.addSubscriber(duke);
    newsLetter.addNewEmail("Lambda Java Challenge");
    newsLetter.removeSubscriber(duke);

    newsLetter.addSubscriber(juggy);
    newsLetter.addSubscriber(dock);
    newsLetter.addNewEmail("Virtual Threads Java Challenge");
  }

}

这是我们代码的输出:


Email for: Duke | Content:Lambda Java Challenge
Email for: Juggy | Content:Virtual Threads Java Challenge
Email for: Moby Dock | Content:Virtual Threads Java Challenge

何时使用 Observable 模式

当一个动作发生并且需要通知多个对象时,最好使用 Observable 模式而不是检查一个对象的状态 Object 多次。 想象一下,有 200 多个对象需要接收通知; 在这种情况下,您必须将 200 乘以检查发生的次数。

通过使用 Observable 模式,通知只会对所有订阅者发生一次。 这是一个巨大的性能提升,也是一种有效的代码优化。 此代码可以轻松扩展或更改。

反应式编程范式到处都使用 Observable 模式。 如果你曾经使用过 Angular,那么你就会知道使用 Observable 组件是很常见的。 响应式组件经常被其他事件和逻辑观察到,当满足特定条件时,组件将执行一些动作。

结论

以下是关于 Observable 设计模式需要记住的要点:

    Observable 使用开闭 SOLID 原则。 这意味着我们可以扩展 addSubscriberremoveSubscriber 方法而无需更改方法签名。 原因是它收到了 Subject 接口而不是直接实现。 这 Observer 界面观察发生在 Subject. 这 Subject 也被称为 Observable 因为这是一个将被观察的主题。 它也可能被称为 Publisher 因为它发布事件。 这 Observer 也被称为 Subscriber 因为它订阅了 Subject/Publisher. 这 Observer 当动作发生时被通知。 如果我们不使用 Observable 设计模式, Subscriber 将不得不不断轮询以了解事件是否发生,这对您的应用程序性能来说可能是可怕的。 Observable 是一种更有效的解决方案。

阅读更多

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注