首页 > 其他分享 >【软件设计模式】 观察者模式详解

【软件设计模式】 观察者模式详解

时间:2024-08-13 16:23:38浏览次数:16  
标签:订阅 软件设计 通知 void 观察者 模式 详解 health 发布者

观察者模式

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

这种模式特别适合于实现分布式系统中的事件处理系统,以及在需要在应用中实现广播通信时使用。

组成

  • 发布者(Subject)
    会向观察者发送值得关注的事件。 事件会在发布者自身状态改变或执行特定行为后发生。 发布者维护了一个订阅列表,并提供了添加、删除和通知观察者的方法。
    当新事件发生时,发布者会遍历订阅列表并调用每个订阅者对象的通知方法。 该方法是在订阅者接口中声明的。
  • 观察者(Observer)
    观察者是一个依赖于发布者状态的对象,它会在被观察者状态发生变化时接收到通知并作出相应的处理。观察者定义了一个update()方法,该方法可以拥有多个参数, 使发布者能在更新时传递事件的详细信息,用于在接收到通知后更新自身状态或执行相应的操作。

在这里插入图片描述

适用场景

  • 当一个对象状态的改变需要改变其他对象, 或实际对象是事先未知的或动态变化的时, 可使用观察者模式。

    当你使用图形用户界面类时通常会遇到一个问题。 比如,你创建了自定义按钮类并允许客户端在按钮中注入自定义代码, 这样当用户按下按钮时就会触发这些代码。观察者模式允许任何实现了订阅者接口的对象订阅发布者对象的事件通知。 你可在按钮中添加订阅机制, 允许客户端通过自定义订阅类注入自定义代码。

  • 当应用中的一些对象必须观察其他对象时,可使用该模式。

    但仅能在有限时间内或特定情况下使用。订阅列表是动态的, 因此订阅者可随时加入或离开该列表。

实现方式

  1. 仔细检查你的业务逻辑,试着将其拆分为两个部分: 独立于其他代码的核心功能将作为发布者; 其他代码则将转化为一组订阅类。

  2. 声明订阅者接口。 该接口至少应声明一个update()方法。

  3. 声明发布者接口并定义一些接口来在列表中添加和删除订阅对象。 记住发布者必须仅通过订阅者接口与它们进行交互。

  4. 确定存放实际订阅列表的位置并实现订阅方法。 通常所有类型的发布者代码看上去都一样, 因此将列表放置在直接扩展自发布者接口的抽象类中是显而易见的。 具体发布者会扩展该类从而继承所有的订阅行为。
    但是, 如果你需要在现有的类层次结构中应用该模式, 则可以考虑使用组合的方式: 将订阅逻辑放入一个独立的对象, 然后让所有实际订阅者使用该对象。

  5. 创建具体发布者类。 每次发布者发生了重要事件时都必须通知所有的订阅者。

  6. 在具体订阅者类中实现通知更新的方法。 绝大部分订阅者需要一些与事件相关的上下文数据。 这些数据可作为通知方法的参数来传递。

    但还有另一种选择。 订阅者接收到通知后直接从通知中获取所有数据。 在这种情况下, 发布者必须通过更新方法将自身传递出去。 另一种不太灵活的方式是通过构造函数将发布者与订阅者永久性地连接起来。

  7. 客户端必须生成所需的全部订阅者, 并在相应的发布者处完成注册工作。

意义

  • 观察者模式实现了被观察者和观察者之间的松耦合,被观察者并不知道具体有哪些观察者,而观察者也不知道被观察者的具体细节,它们只是通过接口进行通信。
  • 被观察者在状态发生变化时会通知所有的观察者,观察者接收到通知后可以执行相应的操作。
  • 观察者模式实现了一对多的依赖关系,一个被观察者可以有多个观察者,并且这些观察者可以同时监听被观察者的状态变化。
  • 观察者模式允许动态地添加和删除观察者,被观察者并不依赖于具体的观察者对象,从而实现了更大的灵活性。
  • 你无需修改发布者代码就能引入新的订阅者类 (如果是发布者接口则可轻松引入发布者类)。

软件设计原则:开闭原则好莱坞原则

示例

假设我们在开发一个游戏,游戏中有一个英雄(Hero)角色,当英雄的生命值发生变化时,需要通知游戏界面(UI)更新显示的生命值,同时也要通知成就系统(AchievementSystem)检查是否触发了某些成就。

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

// 被观察者接口
interface Subject {
    void attach(Observer observer); // registerObserver
    void detach(Observer observer); // removeObserver
    void notifyObservers();
}

class Hero implements Subject {
    private int health = 100;
    private List<Observer> observers = new ArrayList<>();

    public void setHealth(int health) {
        this.health = health;
        notifyObservers();
    }

    public int getHealth() {
        return health;
    }

    @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(this.health);
        }
    }
}

class GameUI implements Observer {
    @Override
    public void update(int health) {
        System.out.println("UI: Hero health updated to " + health);
    }
}

class AchievementSystem implements Observer {
    @Override
    public void update(int health) {
        if (health == 100) {
            System.out.println("Achievement unlocked: Full Health");
        }
    }
}

public class ObserverDemo {
    public static void main(String[] args) {
        Hero hero = new Hero();
        GameUI ui = new GameUI();
        AchievementSystem achievementSystem = new AchievementSystem();

        // 注册观察者
        hero.attach(ui);
        hero.attach(achievementSystem);

        // 改变英雄的生命值,观察者会被通知
        hero.setHealth(90);
        hero.setHealth(100); // 这将触发成就系统的通知
    }                           
}

观察者模式就像是订阅了某个主题(如新闻、博客),当有新内容时,所有订阅者都会收到通知。在我们的游戏例子中,Hero就像是一个新闻发布者,而GameUI和AchievementSystem就像是订阅了这个新闻的读者,当新闻(即英雄的生命值变化)发布时,所有读者都会得到更新。

在这里插入图片描述

标签:订阅,软件设计,通知,void,观察者,模式,详解,health,发布者
From: https://blog.csdn.net/Lewiz_124/article/details/141165413

相关文章

  • [全文]买椟还珠和坏事变好事?《分析模式》漫谈19
    DDD领域驱动设计批评文集做强化自测题获得“软件方法建模师”称号《软件方法》各章合集“AnalysisPatterns”的第一章有这么一句:Modelinginaprogramminglanguagealsopresentsthe danger oftyingthemodelstothatlanguage.Themodelmayusefeaturesoft......
  • 海外市场风向标:Shein全面发力半托管模式
    Shein,一个迅速崛起的全球在线时尚零售平台,以其快速的时尚反应和亲民的价格,赢得了全球消费者的青睐。自2023年起,SHEIN致力于加强其平台架构,通过提供全面的平台代运营服务、商家自我管理的运营方式和半托管模式,来满足多样化的跨境销售需求。这些模式旨在为各类跨境商家提供合适的......
  • Java注解详解:@Async异步
    使用@Async进行异步方法调用@Async是Spring框架里的一个小工具,能让你的方法在后台偷偷跑起来,不影响主线程的工作。这个方法特别适合用来处理那些不需要立即给用户反馈的任务,比如发个邮件啊,处理个大文件啥的。1.配置异步支持首先,你得在Spring配置类里开个绿灯,让......
  • [开题报告]FLASK框架涉外商务协会管理软件设计3j3jv(源码+论文)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景随着全球经济一体化的深入发展,涉外商务活动日益频繁,商务协会作为促进国际交流与合作的重要平台,其管理效率与服务质量直接关系到会员企业的......
  • c语言-指针详解
    一指针变量1.1指针的概念本质上指针就是地址,我们所说的指针就是指针变量,指针变量是一个用来存放地址的指针。我们知道计算机上CPU(中央处理器)在处理数据的时候,需要的数据是在内存中读取的,处理后的数据也会放回内存中,那我们电脑上内存是8GB/16GB/32GB等,那这些内存空......
  • 创建型模式--单例模式
    饿汉模式提前创建好了//饿汉式publicclassSingleton{privatestaticfinalSingletoninstance=newSingleton();privateSingleton(){//私有构造方法,防止外部实例化}publicstaticSingletongetInstance(){returnins......
  • C语言操作符详解
    【揭秘!】这里有你从未听过的独特见解,快来点赞关注,开启智慧之旅 目录1.操作符的分类2.二进制和进制转换2.1二进制转十进制 2.2 十进制转二进制2.3 二进制转八进制2.4 二进制转十六进制3.原码、反码、补码4.位移操作符4.1左移操作符4.2右移操作符5.位操作符......
  • `find` 命令详解
    find命令是Unix和类Unix系统(如Linux)中的一个强大工具,用于在目录树中搜索文件和目录。它提供了多种选项来进行复杂的搜索,可以根据文件的名称、类型、时间、大小等条件筛选文件。以下是find命令的详细介绍,包括常用选项和示例。基本语法find[路径][选项][测试条件][操......
  • chapter11------进入保护模式
    全局描述符表(GDT)这里要先说明下,保护模式下对内存段的访问是有限制的,简单来说就是你不能再随意的访问了,只能访问授权给你的,然后段的访问限制等等信息就记载在一个叫做全局描述表里段描述符段描述符存储了某个段的具体信息,就像我们每个人的档案一样,记录着我们的信息然后段描述......
  • KVM网络模式
    在KVM(Kernel-basedVirtualMachine)虚拟化环境中,有几种不同的网络模式可以用来配置虚拟机(VMs)的网络连接。这些模式主要通过libvirt工具来设置,libvirt是一个管理KVM和其他虚拟化技术的工具集。下面是KVM中常用的几种网络模式:Bridge(桥接)模式:描述:在这种模式下,虚拟机与宿......