Java设计模式之观察者模式(Observer模式)介绍

Java设计模式之观察者模式(Observer模式)介绍

观察者模式,也叫做发布订阅模式,是一种常用的设计模式。它定义了一种一对多的关系,让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时,所有依赖于它的对象都将得到通知并被自动更新。

观察者模式的结构

观察者模式由四个角色组成:抽象主题角色、具体主题角色、抽象观察者角色和具体观察者角色。

  • 抽象主题角色:抽象主题角色定义了主题对象的基本操作,如增加、删除和通知观察者对象的方法。
  • 具体主题角色:具体主题角色引用具体观察者对象,并实现抽象主题角色中的增加、删除和通知观察者的方法。通常具体主题角色是一个类,其中包含方法来设置和获取状态,并在状态改变时通知观察者对象。
  • 抽象观察者角色:抽象观察者角色声明了更新的方法,当被通知时调用以更新自己。
  • 具体观察者角色:具体观察者角色实现抽象观察者角色中定义的更新方法。通常具体观察者角色使用具体主题角色通知观察者对象状态的变化。

观察者模式的示例

下面我们通过两个示例来演示观察者模式的使用:

示例1:气象站

假设我们要开发一个气象站程序,该程序能够实时显示当前气温、湿度和气压。

需要考虑的问题是如何方便地扩展该程序——比如增加日志模块,将信息记录到文件中;增加短信提醒模块,将信息发送给用户等等。

这时候我们可以使用观察者模式。将气象站作为主题对象,将日志模块和用户模块作为观察者对象进行注册,当气象站数据发生更新时,会通知所有的观察者对象。

具体实现需要定义四个角色:

  • 抽象主题角色:气象站主题,定义主题对象应该具有的操作。
  • 具体主题角色:气象站,继承抽象主题角色,实现具体的操作方法。
  • 抽象观察者角色:观察者,定义观察者对象应该具有的操作。
  • 具体观察者角色:日志模块和用户模块,继承抽象观察者角色,实现更新方法。

示例代码如下:

// 抽象主题角色:气象站
interface WeatherStation {
    void addObserver(Observer observer); // 增加观察者
    void removeObserver(Observer observer); // 删除观察者
    void notifyObservers(); // 通知观察者
}

// 具体主题角色:气象站
class ConcreteWeatherStation implements WeatherStation {
    private List<Observer> observers; // 观察者列表
    private float temperature; // 当前温度
    private float humidity; // 当前湿度
    private float pressure; // 当前气压

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

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

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

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

    public void setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        notifyObservers();
    }
}

// 抽象观察者角色:观察者
interface Observer {
    void update(float temperature, float humidity, float pressure); // 更新方法
}

// 具体观察者角色:日志模块
class LogModule implements Observer {
    @Override
    public void update(float temperature, float humidity, float pressure) {
        // 将气象数据记录到日志文件中
        System.out.println("Logging: temperature=" + temperature + ", humidity=" + humidity + ", pressure=" + pressure);
    }
}

// 具体观察者角色:用户模块
class UserModule implements Observer {
    @Override
    public void update(float temperature, float humidity, float pressure) {
        // 将气象数据发送给用户
        System.out.println("User: temperature=" + temperature + ", humidity=" + humidity + ", pressure=" + pressure);
    }
}

示例2:游戏角色属性

假设我们正在开发一款RPG游戏,游戏中有多种属性,如生命值、攻击力、防御力等。当游戏中角色的属性发生变化时,游戏内的各种界面需要及时更新这些变化。

这时候我们同样可以使用观察者模式。将游戏角色作为主题对象,将各种属性界面作为观察者对象进行注册,当角色属性发生更新时,会通知所有的观察者对象。

具体实现需要定义四个角色:

  • 抽象主题角色:游戏角色,定义主题对象应该具有的操作。
  • 具体主题角色:具体游戏角色,继承抽象主题角色,实现具体的操作方法。
  • 抽象观察者角色:属性界面,定义观察者对象应该具有的操作。
  • 具体观察者角色:生命值界面、攻击力界面和防御力界面,继承抽象观察者角色,实现更新方法。

示例代码如下:

// 抽象主题角色:游戏角色
interface GameCharacter {
    void addObserver(Observer observer); // 增加观察者
    void removeObserver(Observer observer); // 删除观察者
    void notifyObservers(); // 通知观察者
}

// 具体主题角色:具体游戏角色
class ConcreteGameCharacter implements GameCharacter {
    private List<Observer> observers; // 观察者列表
    private int hp; // 当前生命值
    private int attack; // 当前攻击力
    private int defense; // 当前防御力

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

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

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

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

    public void setHp(int hp) {
        this.hp = hp;
        notifyObservers();
    }

    public void setAttack(int attack) {
        this.attack = attack;
        notifyObservers();
    }

    public void setDefense(int defense) {
        this.defense = defense;
        notifyObservers();
    }
}

// 抽象观察者角色:属性界面
interface Observer {
    void update(int hp, int attack, int defense); // 更新方法
}

// 具体观察者角色:生命值界面
class HpPanel implements Observer {
    @Override
    public void update(int hp, int attack, int defense) {
        // 刷新生命值界面
        System.out.println("HpPanel: hp=" + hp);
    }
}

// 具体观察者角色:攻击力界面
class AttackPanel implements Observer {
    @Override
    public void update(int hp, int attack, int defense) {
        // 刷新攻击力界面
        System.out.println("AttackPanel: attack=" + attack);
    }
}

// 具体观察者角色:防御力界面
class DefensePanel implements Observer {
    @Override
    public void update(int hp, int attack, int defense) {
        // 刷新防御力界面
        System.out.println("DefensePanel: defense=" + defense);
    }
}

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java设计模式之观察者模式(Observer模式)介绍 - Python技术站

(0)
上一篇 2023年6月15日
下一篇 2023年6月15日

相关文章

  • Java实现将数字日期翻译成英文单词的工具类实例

    Java实现将数字日期翻译成英文单词的工具类实例,可以帮助我们将数字日期转换成更易于阅读和理解的英文单词格式。下面我来详细讲解该实现的完整攻略: 1. 准备工作 首先,我们需要创建一个Java工程,将代码存放在该工程中。在工程中创建一个名为DateUtil的工具类,用于实现数字日期翻译成英文单词的功能。 2. 定义工具类 在DateUtil工具类中,我们需要…

    Java 2023年5月19日
    00
  • 解决java.util.NoSuchElementException异常的问题

    解决java.util.NoSuchElementException异常通常需要对代码进行逐步的排查和调试。以下是完整攻略: 1. 异常类型解释 NoSuchElementException异常通常意味着在访问集合或迭代器时出现了问题,例如使用Scanner在输入流中获取下一个输入时,如果此时输入流已经到达了尾部,就会抛出该异常。 2. 排查调试步骤 解决j…

    Java 2023年5月27日
    00
  • Struts 2 实现Action的几种方式

    Struts 2 实现 Action 的几种方式包括以下几种:基于方法、基于类、基于接口、基于注解,以及自定义 Action。 基于方法 这种方式是在 Action 类中定义不同的方法来处理不同的请求,例如: public class UserAction{ public String list(){ // 处理列表请求 return "list&…

    Java 2023年5月20日
    00
  • 在JavaScript中使用for循环的方法

    在 JavaScript 中,for 循环用于重复执行某些代码。for 循环通常用于遍历数组或对象,执行相同的代码多次。 基本格式为: for (初始值; 终止条件; 增量) { // 要执行的代码块 } 其中: 初始值:定义用于循环计数的变量,并设置初始值。 终止条件:定义循环运行条件,如果该条件为 true,则循环继续执行;如果为 false,则循环结束…

    Java 2023年5月26日
    00
  • SpringMVC 重定向参数RedirectAttributes实例

    下面我将详细讲解“SpringMVC 重定向参数RedirectAttributes实例”的完整攻略。 1. 概述 在SpringMVC中,通过重定向(Redirect)实现页面的跳转是常见的做法。但有时可能需要将一些参数传递到重定向后的页面中。例如,一个操作成功后,我们需要将提示消息传递给下一个页面。这时,就需要使用到RedirectAttributes这…

    Java 2023年6月15日
    00
  • SpringBoot整合SpringSecurity实现权限控制之实现多标签页

    下面是“SpringBoot整合SpringSecurity实现权限控制之实现多标签页”的完整攻略: 环境搭建 首先,您需要在本地环境中安装下列软件和工具: JDK 1.8或更高版本 Maven 3.2或更高版本 IntelliJ IDEA或 Eclipse 其次,在pom.xml中添加Spring Security和Thymeleaf依赖: <dep…

    Java 2023年5月20日
    00
  • Java面向对象编程的三大特征

    Java面向对象编程的三大特征分别是封装、继承和多态。下面分别来详细讲解: 封装 封装是面向对象编程的一个非常重要的特征,它是指将数据和方法结合起来,形成一个独立的整体,对外部隐藏对象内部的实现细节。在Java中,通过访问修饰符(public、private、protected)来实现封装。 示例1:下面的代码展示了一个简单的Java类,它使用封装来隐藏内部…

    Java 2023年5月26日
    00
  • tomcat简介_动力节点Java学院整理

    Tomcat简介 Tomcat是一种开源的Servlet容器和JSP引擎,它使得Java代码可以在Web服务器上运行,可以用于纯Java的Web开发。以下是动力节点Java学院整理的一份Tomcat简介攻略。 安装 首先,我们需要在官网上下载对应的Tomcat版本,并解压缩到指定的目录。 配置 Tomcat的主要配置文件是conf文件夹中的server.xm…

    Java 2023年6月2日
    00
合作推广
合作推广
分享本页
返回顶部