14 设计模式值观察者模式(书籍发布通知案例)

一、观察者模式定义

在日常开发中,我们经常会遇到一种场景:某个对象的状态发生变化时,需要通知并更新其他相关对象。这时,观察者模式便成为了解决问题的有效方案。观察者模式是一种常见的设计模式,它允许一个对象的状态变化自动通知依赖于它的其他对象。

观察者模式(Observer Pattern)是一种行为型设计模式,定义了对象间的一对多依赖关系,使得每当一个对象的状态发生变化时,所有依赖于它的对象都会自动收到通知并更新。

换句话说,观察者模式允许一个对象(称为被观察者 )将其状态的变化推送给多个观察者(观察者),而观察者则根据状态变化做出相应的处理。


二、观察者模式组成

观察者模式包含以下几个重要组成部分:

1.Subject(主题/被观察者)

被观察者是状态变化的源头,它会维护一组观察者对象。

被观察者提供接口让观察者注册、注销,并在状态发生变化时通知观察者。

2.Observer(观察者)

观察者是依赖于被观察者的对象,当被观察者的状态发生变化时,观察者会接收到通知并做出相应的处理。

观察者接口通常定义一个 update 方法,用于接受通知。

3.ConcreteSubject(具体被观察者)

具体被观察者实现了 Subject 接口,并在状态变化时通知所有已注册的观察者。

4.ConcreteObserver(具体观察者)

具体观察者实现了 Observer 接口,并在接收到通知时更新自身的状态。


三、观察者模式的工作原理

在观察者模式中,被观察者 通过 register 方法注册多个观察者。被观察者的状态一旦发生变化,调用 notify 方法将通知所有已注册的观察者,观察者会通过 update 方法接收并处理这些变化。


四、案例讲解:书籍发布通知

为了更好地理解观察者模式,下面我们通过一个书籍发布通知的例子来演示观察者模式的实际应用。

1. 设计接口与类

在本例中,我们将书籍发布看作是被观察者,而读者则是观察者。当新书发布时,我们需要通知所有注册的读者,告诉他们新书的名字。

(1)Observer 接口

java 复制代码
public interface Observer {
    void update(String bookName);
}

Observer 接口定义了一个 update 方法,用于接收新书发布的通知,并通过书名来更新观察者的状态。

(2)ConcreteObserver

java 复制代码
public class ConcreteObserver implements Observer {
    private String readerName;

    public ConcreteObserver(String readerName) {
        this.readerName = readerName;
    }

    @Override
    public void update(String bookName) {
        System.out.println(readerName + ", 收到新书发布通知:" + bookName);
    }
}

ConcreteObserver 是具体的观察者类,它保存读者的姓名,并在接收到新书发布通知时,输出一条消息来告诉读者。

(3)Subject 接口

java 复制代码
public interface Subject {
    void registerObserver(Observer observer);  // 注册观察者
    void removeObserver(Observer observer);    // 移除观察者
    void notifyObservers();                    // 通知观察者
}

Subject 接口定义了三个方法:注册观察者、移除观察者和通知所有观察者。

(4)ConcreteSubject

java 复制代码
public class ConcreteSubject implements Subject {
    private List<Observer> observers;
    private String bookName;

    public ConcreteSubject() {
        observers = new ArrayList<>();
    }

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

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

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(bookName);
        }
    }

    // 新书发布方法,更新书名并通知所有观察者
    public void publishBook(String bookName) {
        this.bookName = bookName;
        notifyObservers();
    }
}

ConcreteSubject 类实现了 Subject 接口。它维护一个观察者列表,并在新书发布时通知所有已注册的观察者。

2.测试类

java 复制代码
public class TestObserverPattern {
    public static void main(String[] args) {
        ConcreteSubject bookPublisher = new ConcreteSubject();
        Observer reader1 = new ConcreteObserver("Theodore_1022");
        Observer reader2 = new ConcreteObserver("Andy");
        Observer reader3 = new ConcreteObserver("小胖");

        bookPublisher.registerObserver(reader1);
        bookPublisher.registerObserver(reader2);
        bookPublisher.registerObserver(reader3);

        System.out.println("发布新书:超越音符");
        bookPublisher.publishBook("超越音符");

        bookPublisher.removeObserver(reader2);

        System.out.println("发布新书:记得");
        bookPublisher.publishBook("记得");
    }
}

3. 运行输出

发布新书:超越音符

Theodore_1022, 收到新书发布通知:超越音符

Andy, 收到新书发布通知:超越音符

小胖, 收到新书发布通知:超越音符

发布新书:记得

Theodore_1022, 收到新书发布通知:记得

小胖, 收到新书发布通知:记得


五、观察者模式的优缺点

1.优点

  • 松耦合 :观察者模式将观察者与被观察者解耦。被观察者不需要知道观察者的具体实现,只需要调用 update 方法。
  • 动态更新:可以动态地添加或删除观察者,系统可以根据需要进行扩展。
  • 适用于一对多的场景:当一个对象的状态变化需要同时影响多个对象时,观察者模式是理想的选择。

2.缺点

  • 通知过多:当观察者较多时,通知会影响性能。如果被观察者频繁发生变化,可能会引发性能问题。
  • 依赖过度:观察者模式会导致观察者过于依赖被观察者的实现,可能会影响代码的灵活性。

六、总结

观察者模式是一种非常适合"一对多"场景的设计模式。在需要解耦的场景中,它为对象之间的通信提供了灵活、低耦合的方式。本次案例中,我们通过"书籍发布"的实际例子,清晰地展示了如何实现观察者模式,并将模式的各个组成部分一一拆解。

通过实现观察者模式,我们能够在系统中自动管理对象间的依赖关系,确保在状态变化时,系统能够自动进行更新,而无需手动干预。这使得代码的扩展性和可维护性得到了显著提升。

相关推荐
上理考研周导师2 分钟前
【单片机原理】第1章 微机基础知识,运算器,控制器,寄存器,微机工作过程,数制转换
算法
檀越剑指大厂8 分钟前
【Python系列】Python中的`any`函数:检查“至少有一个”条件满足
开发语言·python
I_Am_Me_1 小时前
【JavaEE初阶】线程安全问题
开发语言·python
IT猿手1 小时前
基于PWLCM混沌映射的麋鹿群优化算法(Elk herd optimizer,EHO)的多无人机协同路径规划,MATLAB代码
算法·elk·机器学习·matlab·无人机·聚类·强化学习
运维&陈同学1 小时前
【Elasticsearch05】企业级日志分析系统ELK之集群工作原理
运维·开发语言·后端·python·elasticsearch·自动化·jenkins·哈希算法
ZHOUPUYU2 小时前
最新 neo4j 5.26版本下载安装配置步骤【附安装包】
java·后端·jdk·nosql·数据库开发·neo4j·图形数据库
Q_19284999063 小时前
基于Spring Boot的找律师系统
java·spring boot·后端
ZVAyIVqt0UFji4 小时前
go-zero负载均衡实现原理
运维·开发语言·后端·golang·负载均衡
谢家小布柔4 小时前
Git图形界面以及idea中集合Git使用
java·git
loop lee4 小时前
Nginx - 负载均衡及其配置(Balance)
java·开发语言·github