程序员必知!观察者模式的实战应用与案例分析

2024-01-09 14:44:06

Java设计模式 - 程序员古德

观察者模式定义了一对多的依赖关系,让多个观察者同时监听一个主题对象,当主题状态改变时,所有观察者都会自动收到通知并更新,以新闻发布会为例,新闻机构发布消息时,所有关注的记者和订阅者都会收到通知并进行独立处理,这就是典型的观察者模式应用,该模式实现了松耦合,主题和观察者之间不需相互了解具体实现细节。

定义

程序员必知!观察者模式的实战应用与案例分析 - 程序员古德

观察者模式它定义了对象间的一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象,当主题对象状态发生改变时,它的所有依赖者(观察者)都会自动收到通知并更新。

举个现实业务中的形象例子:想象一个新闻发布会的场景,在这个场景中,新闻机构发布了一些重要消息,而记者和订阅者(观察者)都希望尽快得到这些消息,当新闻机构发布新消息时,所有关注的记者和订阅者都会收到通知,并根据这些消息进行自己的报道或行动。

具体来说:

  1. 新闻机构:负责产生和发布新闻消息,当有新的消息时,它会通知所有关注的记者和订阅者。
  2. 记者和订阅者(观察者):他们关注新闻机构,希望在其发布新消息时得到通知,每个记者或订阅者都可以根据接收到的消息进行独立处理,比如撰写报道、更新社交媒体状态等。

在这个例子中,新闻机构和记者/订阅者之间的关系就是典型的观察者模式,新闻机构不需要知道具体有哪些记者或订阅者在关注它,它只需要在适当的时候发布消息,同样,记者和订阅者也不需要知道新闻机构是如何产生消息的,他们只需要在消息发布时得到通知并进行处理。

代码案例

程序员必知!观察者模式的实战应用与案例分析 - 程序员古德

反例

在未使用观察者模式的情况下,通常会采用直接调用或轮询的方式来通知依赖对象状态的改变,这种方式不仅增加了代码之间的耦合性,还可能导致效率低下和资源浪费,下面是一个未使用观察者模式的反例代码:

// 主题类,负责维护状态并通知观察者(但在这个例子中,并没有实现观察者模式)  
public class Subject {  
    private String state;  
      
    // 假设这是唯一关注该主题的“观察者”(实际上这并不是观察者模式的实现)  
    private ConcreteObserver observer;  
      
    public Subject(ConcreteObserver observer) {  
        this.observer = observer;  
    }  
      
    public void setState(String state) {  
        this.state = state;  
        // 直接调用观察者的更新方法  
        observer.update(state);  
    }  
      
    public String getState() {  
        return state;  
    }  
}  
  
// 观察者接口(在这个反例中,它并没有起到应有的作用)  
public interface Observer {  
    void update(String state);  
}  
  
// 具体的观察者类  
public class ConcreteObserver implements Observer {  
    private String observerState;  
      
    @Override  
    public void update(String state) {  
        this.observerState = state;  
        System.out.println("ConcreteObserver's state updated to: " + state);  
    }  
      
    public String getObserverState() {  
        return observerState;  
    }  
}  
  
// 客户端代码  
public class Client {  
    public static void main(String[] args) {  
        // 创建观察者  
        ConcreteObserver observer = new ConcreteObserver();  
        // 创建主题并将观察者传入(尽管这里传入了,但并没有利用观察者模式的优点)  
        Subject subject = new Subject(observer);  
          
        // 更改主题状态  
        subject.setState("new state");  
          
        // 输出观察者的状态  
        System.out.println("Observer's state after update: " + observer.getObserverState());  
          
        // 假设需要添加另一个观察者,但由于没有使用观察者模式,这将会很困难  
        // 不得不修改Subject类来适应新的观察者  
    }  
}

在这个例子中,Subject 类直接持有一个 ConcreteObserver 的引用,并在状态改变时直接调用它的 update 方法,这种方式的问题在于:

  1. 紧密耦合:Subject 类与 ConcreteObserver 类紧密耦合在一起,如果要添加新的观察者或者更改现有的观察者,就不得不修改 Subject 类的代码。
  2. 不易扩展:如果想要添加多个观察者,就不得不为每个观察者都添加一个引用,并在 setState 方法中调用它们的 update 方法。
  3. 违反开闭原则:对 Subject 类的任何修改都可能引入新的错误,并且违反了开闭原则。

正例

下面是一个使用观察者模式的正例代码实现,在这个例子中,有一个Subject接口,它定义了注册、移除和通知观察者的方法,ConcreteSubject类实现了这个接口,并维护了一个观察者列表,Observer是一个接口,定义了观察者更新其状态的方法,ConcreteObserver实现了这个接口,如下代码:

// 观察者接口  
public interface Observer {  
    void update(String state);  
}  
  
// 具体观察者类  
public class ConcreteObserver implements Observer {  
    private String observerState;  
      
    @Override  
    public void update(String state) {  
        // 更新观察者的状态  
        this.observerState = state;  
        System.out.println("ConcreteObserver's state updated to: " + state);  
    }  
}  
  
// 主题接口  
public interface Subject {  
    void registerObserver(Observer observer);  
    void removeObserver(Observer observer);  
    void notifyObservers(String state);  
}  
  
// 具体主题类  
import java.util.ArrayList;  
import java.util.List;  
  
public class ConcreteSubject implements Subject {  
    // 维护一个观察者列表  
    private List<Observer> observers = new ArrayList<>();  
    private String subjectState;  
      
    @Override  
    public void registerObserver(Observer observer) {  
        observers.add(observer);  
    }  
      
    @Override  
    public void removeObserver(Observer observer) {  
        observers.remove(observer);  
    }  
      
    @Override  
    public void notifyObservers(String state) {  
        // 遍历观察者列表并通知每个观察者  
        for (Observer observer : observers) {  
            observer.update(state);  
        }  
    }  
      
    // 设置主题状态的方法,状态改变时通知观察者  
    public void setState(String state) {  
        this.subjectState = state;  
        notifyObservers(state);  
    }  
      
    public String getState() {  
        return subjectState;  
    }  
}  
  
// 客户端代码  
public class Client {  
    public static void main(String[] args) {  
        // 创建具体主题和观察者  
        ConcreteSubject subject = new ConcreteSubject();  
        Observer observer = new ConcreteObserver();  
          
        // 注册观察者  
        subject.registerObserver(observer);  
          
        // 改变主题状态  
        subject.setState("new state");  
          
        // 取消注册观察者  
        subject.removeObserver(observer);  
          
        // 再次改变主题状态,此时观察者不再接收通知  
        subject.setState("another new state");  
    }  
}

运行结果将会是:

ConcreteObserver's state updated to: new state

这里展示了观察者模式的核心思想:主题维护一个观察者列表,当主题状态发生变化时,所有注册的观察者都会收到通知,这种方式降低了主题和观察者之间的耦合性,使得可以独立地改变主题或观察者,而不会影响到对方,同时,它也可以动态地添加或移除观察者,从而增加了代码的灵活性和可扩展性。

核心总结

程序员必知!观察者模式的实战应用与案例分析 - 程序员古德

观察者模式是一种行为设计模式,它能够在对象之间建立一种一对多的依赖关系,这样一来,当一个对象改变状态时,所有依赖于它的对象都会得到通知并自动更新。主要体现在,1、主题与观察者之间代码依赖度低,双方只依赖于抽象接口,而不是具体实现,易于扩展和维护,2、主题状态变化时,可以自动通知所有已注册的观察者,实现一对多的通信。在使用观察者模式时需要考虑一些注意点,1、如果观察者之间或间接地相互依赖,可能引发循环调用和系统崩溃,2、在观察者数量多或通知操作复杂时,频繁的通知可能导致性能下降,3、在多线程环境下,通知过程可能需要同步措施来避免数据不一致问题。

关注我,每天学习互联网编程技术 - 程序员古德

文章来源:https://blog.csdn.net/qusikao/article/details/135478134
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。