跟着GPT学设计模式之观察者模式

你好,这里是codetrend专栏“跟着GPT学设计模式”。

引言

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

观察者模式(Observer Design Pattern)也被称为发布订阅模式(Publish-Subscribe Design Pattern)。一般情况下,被依赖的对象叫作被观察者(Observable),依赖的对象叫作观察者(Observer)。

不过,在实际的项目开发中,这两种对象的称呼是比较灵活的,有各种不同的叫法,比如:Subject-Observer、Publisher-Subscriber、Producer-Consumer、EventEmitter-EventListener、Dispatcher-Listener。

在观察者模式中,有两个主要角色:主题(Subject)和观察者(Observer)。主题是被观察的对象,它维护了一个观察者列表,并提供方法用于添加、删除和通知观察者。

观察者是监听主题的对象,它定义了一个更新的方法,在主题状态改变时被调用。

观察者模式的一般工作流程:

  • 主题对象维护一个观察者列表,并提供方法用于注册、注销和通知观察者。
  • 观察者对象实现一个更新方法,用于在主题状态改变时被调用。
  • 当主题的状态发生改变时,它会遍历观察者列表,调用每个观察者的更新方法。
  • 观察者根据接收到的通知进行相应的操作,以使自身状态与主题保持一致。

使用 Mermaid 语法类图展示观察者模式的示意图如下:

classDiagram
    class Subject {
        + attach(Observer observer)
        + detach(Observer observer)
        + notifyObservers()
        # observers: Observer[]
    }

    class Observer {
        + update()
    }

    class ConcreteSubject {
        - state
        + getState()
        + setState(state)
    }

    class ConcreteObserver {
        + update()
    }

    Subject <|-- ConcreteSubject
    Subject "1" --> "*" Observer
    Observer <|-- ConcreteObserver
    ConcreteSubject --> ConcreteObserver
  • Subject 是主题类,包含了添加、删除和通知观察者的方法。observers 是一个观察者列表,用于存储注册的观察者对象。
  • Observer 是观察者类,定义了一个 update() 方法,用于在主题状态改变时被调用。
  • ConcreteSubject 是具体主题类,继承自 Subject,它有一个额外的 state 属性,表示当前状态,并提供了获取和设置状态的方法。
  • ConcreteObserver 是具体观察者类,继承自 Observer,实现了 update() 方法,根据主题状态的改变来更新自身状态。

这个类图展示了观察者模式的关键组件及它们之间的关系。主题与观察者之间是一对多的关系,主题可以有多个观察者。

当主题状态改变时,它会通过通知方法 notifyObservers() 来遍历观察者列表,并依次调用每个观察者的 update() 方法,从而实现观察者的更新操作。

观察者模式的使用场景

观察者模式在实际应用中有很多场景,以下是一些观察者模式的应用场景的举例:

  • GUI 事件处理:在图形用户界面(GUI)中,观察者模式被广泛应用于事件处理机制。当用户执行某个操作时,比如点击按钮或输入文本,这些操作会触发相应的事件。事件作为主题被通知给注册的观察者,观察者可以根据事件类型做出相应的响应,例如更新界面、执行特定逻辑等。
  • 订阅/发布模式:观察者模式也常被称为订阅/发布模式。在发布者-订阅者系统中,发布者充当主题的角色,订阅者则扮演观察者的角色。发布者负责发布消息,订阅者订阅感兴趣的消息类型,并在消息到达时执行相应的操作。这种模式广泛应用于消息队列系统、事件总线等。
  • 消息通知系统:观察者模式也可以用于构建消息通知系统。例如,一个新闻平台可以作为主题,用户可以选择订阅感兴趣的新闻类别作为观察者。当新闻发布时,平台会通知所有订阅了该类别的用户,并将新闻推送给他们。
  • 游戏开发中的事件管理:在游戏开发中,观察者模式常被用于事件管理。例如,游戏角色之间的互动和协作可以通过观察者模式实现。一个角色可以作为主题,其他角色可以注册为观察者。当主题(例如敌人角色)发生改变时,通知所有观察者(例如友方角色)并执行相应的行为。

实际上观察者模式非常灵活,适用于很多具有发布-订阅关系的场景。它提供了一种松耦合的设计方式,使得主题和观察者能够独立变化,并保持一致性。

观察者模式使用注意事项

  • 角色和职责:观察者模式中包括主题(Subject)和观察者(Observer)两个核心角色。主题负责管理观察者的注册、注销以及通知操作,而观察者则定义了接收更新通知并执行相应操作的方法。了解每个角色的职责和关系对于正确使用观察者模式非常重要。
  • 主题状态管理:主题在观察者模式中起到承载和管理状态的作用。当主题状态发生变化时,需要通知所有观察者。因此,需要合理设计和管理主题的状态,并及时触发通知操作。
  • 多线程安全性:在多线程环境下使用观察者模式时,需要考虑线程安全性。例如,在主题状态变化时,可能会遇到多个线程同时修改主题状态或触发通知的情况。需要采取相应的同步措施或使用线程安全的容器来确保并发访问的正确性。
  • 事件传递方式:观察者模式中,主题向观察者传递更新通知的方式可以是同步或异步的。在同步方式下,主题在通知观察者后会等待观察者执行完相应操作,才会继续执行;而在异步方式下,主题通知观察者后立即继续执行,观察者的更新操作在后台进行。了解不同的事件传递方式对系统行为和性能的影响是重要的。

观察者模式编程示例

下面通过一段代码来说明观察者模式的实现。

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

// 主题接口
interface Subject {
    void attach(Observer observer);
    void detach(Observer observer);
    void notifyObservers();
}

// 观察者接口
interface Observer {
    void update();
}

// 具体主题类
class ConcreteSubject implements Subject {
    private List<Observer> observers = new ArrayList<>();

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

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

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

    // 具体主题类的其他方法
    // ...
}

// 具体观察者类
class ConcreteObserver implements Observer {
    @Override
    public void update() {
        System.out.println("观察者收到更新通知,执行相应操作。");
    }
}

public class ObserverPatternExample {
    public static void main(String[] args) {
        // 创建具体主题对象
        ConcreteSubject subject = new ConcreteSubject();

        // 创建具体观察者对象
        ConcreteObserver observer1 = new ConcreteObserver();
        ConcreteObserver observer2 = new ConcreteObserver();

        // 注册观察者
        subject.attach(observer1);
        subject.attach(observer2);

        // 主题发生改变时,通知观察者
        subject.notifyObservers();
    }
}

在上述示例中定义了一个 Subject 接口和一个 Observer 接口,分别表示主题和观察者。

ConcreteSubject 是具体的主题类,实现了 Subject 接口,并包含了维护观察者列表、添加/删除观察者以及通知观察者的方法。

ConcreteObserver 是具体的观察者类,实现了 Observer 接口,并在 update() 方法中定义了观察者接收到更新通知时的操作。

在 main() 方法中创建了具体的主题对象 ConcreteSubject,以及两个具体的观察者对象 observer1 和 observer2。

然后通过 attach() 方法将观察者注册到主题中,然后调用 notifyObservers() 方法通知所有的观察者。当主题发生改变时,所有观察者都会收到更新通知,并执行相应的操作。

以上内容基于 GPT 创建和整理。

关于作者

来自一线全栈程序员nine的探索与实践,持续迭代中。

欢迎关注或者点个赞~

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,463评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,868评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,213评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,666评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,759评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,725评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,716评论 3 415
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,484评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,928评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,233评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,393评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,073评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,718评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,308评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,538评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,338评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,260评论 2 352

推荐阅读更多精彩内容