介绍
观察者模式是行为设计模式之一. 当您对对象的状态感兴趣并希望在有任何更改时收到通知时, 观察者设计模式非常有用. 在观察者模式中, 监视另一个对象状态的对象称为 Observer, 正在被监视的对象称为 Subject.
根据 GoF, 观察者设计模式的意图是;
定义对象之间的一对多依赖关系, 以便当一个对象更改状态时, 将自动通知和更新其所有依赖项.
Subject 包含一个观察者列表, 用于通知其状态的任何变化, 因此它应该提供观察者可以注册和注销自己的方法. Subject 还包含一种方法, 用于通知所有观察者任何更改, 并且可以在通知观察者时发送更新, 或者它可以提供另一种方法来获取更新.
Observer 应该有一个方法来设置要监视的对象, 以及 Subject 将使用的另一个方法来通知它们任何更新.
Java 提供了内置平台, 用于通过 java.util.Observable 类和 java.util.Observer 接口实现 Observer 模式. 但是它没有被广泛使用, 因为实现非常简单, 并且大多数时候我们不希望最终扩展类只是为了实现 Observer 模式, 因为 java 不在类中提供多重继承.
Java 消息服务 (JMS) 使用 Observer 设计模式以及 Mediator 模式, 允许应用程序订阅数据并将数据发布到其他应用程序.
模型 - 视图 - 控制器 (MVC) 框架也使用 Observer 模式, 其中 Model 是 Subject, 而 Views 是观察者, 可以注册以获得对模型的任何更改的通知.
观察者模式 Java 示例
对于我们的观察者模式 java 程序示例, 我们将实现一个简单的 Subject, 观察者可以注册到这个 Subject. 每当有任何新消息发布到 Subject 时, 将通知所有寄存器观察者并且他们可以使用该消息.
根据 Subject 的要求, 这里是基础 Subject 接口, 它定义了由任何具体 Subject 实现的契约方法.
- package com.journaldev.design.observer;
- public interface Subject {
- //methods to register and unregister observers
- public void register(Observer obj);
- public void unregister(Observer obj);
- //method to notify observers of change
- public void notifyObservers();
- //method to get updates from subject
- public Object getUpdate(Observer obj);
- }
接下来我们将为 Observer 创建契约, 将有一个方法将 Subject 附加到观察者, 以及 Subject 要用来通知任何更改的另一个方法.
- package com.journaldev.design.observer;
- public interface Observer {
- //method to update the observer, used by subject
- public void update();
- //attach with subject to observe
- public void setSubject(Subject sub);
- }
现在我们的契约准备好了, 让我们继续我们 Subject 的具体实施.
- package com.journaldev.design.observer;
- import java.util.ArrayList;
- import java.util.List;
- public class MyTopic implements Subject {
- private List<Observer> observers;
- private String message;
- private boolean changed;
- private final Object MUTEX= new Object();
- public MyTopic(){
- this.observers=new ArrayList<>();
- }
- @Override
- public void register(Observer obj) {
- if(obj == null) throw new NullPointerException("Null Observer");
- synchronized (MUTEX) {
- if(!observers.contains(obj)) observers.add(obj);
- }
- }
- @Override
- public void unregister(Observer obj) {
- synchronized (MUTEX) {
- observers.remove(obj);
- }
- }
- @Override
- public void notifyObservers() {
- List<Observer> observersLocal = null;
- //synchronization is used to make sure any observer registered after message is received is not notified
- synchronized (MUTEX) {
- if (!changed)
- return;
- observersLocal = new ArrayList<>(this.observers);
- this.changed=false;
- }
- for (Observer obj : observersLocal) {
- obj.update();
- }
- }
- @Override
- public Object getUpdate(Observer obj) {
- return this.message;
- }
- //method to post message to the topic
- public void postMessage(String msg){
- System.out.println("Message Posted to Topic:"+msg);
- this.message=msg;
- this.changed=true;
- notifyObservers();
- }
- }
注册和取消注册观察者的方法实现非常简单, 额外的方法是 postMessage(), 户端应用程序将使用它将 String 消息发布到主题. 请注意布尔变量, 以跟踪主题状态的变化并用于通知观察者. 此变量是必需的, 因此如果没有更新并且某人调用 notifyObservers(), 则它不会向观察者发送错误通知.
还要注意在 notifyObservers()方法中使用同步, 以确保仅将通知发送给在将消息发布到主题之前注册的观察者.
以下是将观察主题的观察者的实施.
- package com.journaldev.design.observer;
- public class MyTopicSubscriber implements Observer {
- private String name;
- private Subject topic;
- public MyTopicSubscriber(String nm){
- this.name=nm;
- }
- @Override
- public void update() {
- String msg = (String) topic.getUpdate(this);
- if(msg == null){
- System.out.println(name+":: No new message");
- }else
- System.out.println(name+":: Consuming message::"+msg);
- }
- @Override
- public void setSubject(Subject sub) {
- this.topic=sub;
- }
- }
注意 update()方法的实现, 它调用 Subject getUpdate()方法来获取要使用的消息. 我们可以通过将 message 作为参数传递给 update()方法来避免这种调用.
这是一个简单的测试程序, 用于使用我们的 Subject 主题实现.
- package com.journaldev.design.observer;
- public class ObserverPatternTest {
- public static void main(String[] args) {
- //create subject
- MyTopic topic = new MyTopic();
- //create observers
- Observer obj1 = new MyTopicSubscriber("Obj1");
- Observer obj2 = new MyTopicSubscriber("Obj2");
- Observer obj3 = new MyTopicSubscriber("Obj3");
- //register observers to the subject
- topic.register(obj1);
- topic.register(obj2);
- topic.register(obj3);
- //attach observer to subject
- obj1.setSubject(topic);
- obj2.setSubject(topic);
- obj3.setSubject(topic);
- //check if any update is available
- obj1.update();
- //now send message to subject
- topic.postMessage("New Message");
- }
- }
当我们运行上面的程序时, 我们得到以下输出.
- Obj1:: No new message
- Message Posted to Topic:New Message
- Obj1:: Consuming message::New Message
- Obj2:: Consuming message::New Message
- Obj3:: Consuming message::New Message
Java 观察者模式类图
观察者设计模式也称为发布 - 订阅模式. 其中一些实现是:
Swing 中的 java.util.EventListener
- javax.servlet.http.HttpSessionBindingListener
- javax.servlet.http.HttpSessionAttributeListener
- java.util.Observer
- java.util.EventListener
- javax.servlet.http.HttpSessionBindingListener
适用场景:
在以下任何一种情况下使用 Observer 模式
在一个对象中进行更改会导致其他对象发生更改
当抽象有两个方面时, 一个依赖于另一个. 将这些方面封装在单独的对象中可让您独立地改变和重用它们.
当一个对象的更改需要更改其他对象时, 您不知道需要更改多少个对象.
当一个对象应该能够通知其他对象而不假设这些对象是谁. 换句话说, 您不希望这些对象紧密耦合.
这就是 java 中的 Observer 设计模式, 我希望你喜欢它. 与评论分享您的爱, 并与他人分享.
翻译于:
来源: https://www.cnblogs.com/jajian/p/9746433.html