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