设计模式学习(二):Observer观察者模式

简介: 在Observer模式中,当观察对象的状态发生变化时,会通知给观察者。Observer模式适用于根据对象状态进行相应处理的场景。

一、什么是Observer模式



在Observer模式中,当观察对象的状态发生变化时,会通知给观察者。Observer模式适用于根据对象状态进行相应处理的场景。


简单一句话概况就是:观察者会发送观察对象状态变化的通知。

082740e33ca7217f81b41d1909347d09.png

二、Observer模式示例代码



下面示例程序中,observer将观察一个会生成数值的对象,并将它生成的数值结果显示出来。不过,不同的观察者的显示方式不一样。Digitobserver会以数字形式显示数值,而Graphobserver则会以简单的图示形式来显示数值。


2.1 各个类之间的关系


先看一下所有的类和接口:

2c604e76661e8e463c82295e13ed3b7e.png


类图

7bc10ed079909269cac9301af5904b49.png


2.2 Observer接口


Observer接口是表示“观察者”的接口。具体的观察者会实现这个接口。


用于生成数值的NumberGenerator类会调用update方法,将“生成的数值发生了变化,请更新显示内容”的通知发送给Observer。

public interface Observer {
    public abstract void update(NumberGenerator generator);
}


2.3 NumberGenerator类


NumberGenerator类(代码清单17-2)是用于生成数值的抽象类。生成数值的方法( execute方法)和获取数值的方法( getNumber方法)都是抽象方法,需要子类去实现。


addObserver方法用于注册observer,而deleteobserver方法用于删除observer。


notifyObservers方法会向所有的observer发送通知,告诉它们“我生成的数值发生了变化,请更新显示内容”。该方法会调用每个observer的update方法。


public abstract class NumberGenerator {
    //用于保存所有的observer
    private ArrayList observers = new ArrayList();
    //注册observer
    public void addObserver(Observer observer) {
        observers.add(observer);
    }
    //删除observer
    public void deleteObserver(Observer observer) {
        observers.remove(observer);
    }
    //向observer发送通知
    public void notifyObservers() {
        //把每个observer拿出来,调用他的update方法
        Iterator it = observers.iterator();
        while (it.hasNext()) {
            Observer o = (Observer) it.next();
            o.update(this);
        }
    }
    //获取数值
    public abstract int getNumber();
    //生成数值
    public abstract void execute();
}


2.4 RandomNumberGenerator类


RandomNumberGenerator类是NumberGenerator的子类,它会生成随机数。


getNumber方法用于获取number字段的值。execute方法会生成20个0 ~49的随机整数,并通过notifyObservers方法把每次生成结果通知给观察者。

public class RandomNumberGenerator extends NumberGenerator{
    //生成随机数
    private Random random  = new Random();
    //当前数值
    private int number;
    @Override
    public int getNumber() {
        return number;
    }
    @Override
    public void execute() {
        for (int i = 0; i < 20; i++) {
            number = random.nextInt(50);
            notifyObservers();
        }
    }
}


2.5 DigitObserver类


DigitObserver类实现了Observer接口,它的功能是以数字形式显示观察到的数值。


它的update方法接收NumberGenerator的实例作为参数,然后通过调用NumberGenerator类的实例的getNumber方法可以获取到当前的数值,并将这个数值显示出来。

public class DigitObserver implements Observer{
    @Override
    public void update(NumberGenerator generator) {
        System.out.println("DigitObserver:" + generator.getNumber());
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
        }
    }
}


2.6 GraphObserver类


GraphObserver类也实现了Observer接口。

该类会将观察到的数值以*****这样的简单图示的形式显示出来。

public class GraphObserver implements Observer{
    @Override
    public void update(NumberGenerator generator) {
        System.out.println("GraphObserver:");
        int count = generator.getNumber();
        for (int i = 0; i < count; i++) {
            System.out.print("*");
        }
        System.out.println("");
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
        }
    }
}


2.7 Main测试类


Main类生成了一个RandomNumberGenerator类的实例和两个观察者,其中observer1是 DigitObserver类的实例,observer2是GraphObserver类的实例。


在使用addObserver注册观察者后,它还会调用generator.execute方法生成随机数值。

public class Main {
    public static void main(String[] args) {
        NumberGenerator generator = new RandomNumberGenerator();
        Observer observer1 = new DigitObserver();
        Observer observer2 = new GraphObserver();
        generator.addObserver(observer1);
        generator.addObserver(observer2);
        generator.execute();
    }
}


2.8 运行结果


部分运行结果


DigitObserver:21

GraphObserver:

*********************

DigitObserver:7

GraphObserver:

*******

DigitObserver:31

GraphObserver:

*******************************

DigitObserver:24

GraphObserver:

************************


三、拓展思路的要点



3.1 可替换性


使用设计模式的目的之一就是使类成为可复用的组件。


在Observer模式中,有带状态的ConcreteSubject角色和接收状态变化通知的ConcreteObserver角色。连接这两个角色的就是它们的接口(API ) Subject角色和 Observer 角色。


一方面RandomNumberGenerator类并不知道,也无需在意正在观察自己的(自己需要通知的对象)到底是DigitObserver类的实例还是GraphObserver类的实例。不过它知道在它的observers字段中所保存的观察者们都实现了observer接口,一定可以调用它们的update方法。


另一方面,DigitObserver类也无需在意自己正在观察的究竟是RandomNumberGenerator类的实例还是其他XxxxNumberGenerator类的实例。不过,Digitobserver类知道它们是NumberGenerator类的子类的实例,并持有getNumber方法。


我们应该注意到这种可替换性的思想:


利用抽象类和接口从具体类中抽出抽象方法


在将实例作为参数传递至类中,或者在类的字段中保存实例时,不使用具体类型,而是使用抽象类型和接口


这样的实现方式可以帮助我们轻松替换具体类。


3.2 从“观察”变为“通知”


Observer本来的意思是“观察者”,但实际上Observer角色并非主动地去观察,而是被动地接受来自Subject角色的通知。因此,Observer模式也被称为Publish-Subscribe(发布-订阅)模式。个人认为Publish(发布)和 Subscribe(订阅)这个名字可能更加合适。


四、相关的设计模式



4.1 Mediator中介者模式


在Mediator模式中,有时会使用Observer模式来实现Mediator角色与Colleague角色之间的通信。


就“发送状态变化通知”这一点而言,Mediator模式与Observer模式是类似的。不过,两种模式中,通知的目的和视角不同。


在 Mediator模式中,虽然也会发送通知,不过那不过是为了对Colleague角色进行仲裁而已。


而在Observer模式中,将Subject角色的状态变化通知给Observer角色的目的则主要是为了使Subject角色和 Observer角色同步。


相关文章
|
5月前
|
设计模式 缓存 Java
Java设计模式(二):观察者模式与装饰器模式
本文深入讲解观察者模式与装饰器模式的核心概念及实现方式,涵盖从基础理论到实战应用的全面内容。观察者模式实现对象间松耦合通信,适用于事件通知机制;装饰器模式通过组合方式动态扩展对象功能,避免子类爆炸。文章通过Java示例展示两者在GUI、IO流、Web中间件等场景的应用,并提供常见陷阱与面试高频问题解析,助你写出灵活、可维护的代码。
|
3月前
|
设计模式 消息中间件 传感器
Java 设计模式之观察者模式:构建松耦合的事件响应系统
观察者模式是Java中常用的行为型设计模式,用于构建松耦合的事件响应系统。当一个对象状态改变时,所有依赖它的观察者将自动收到通知并更新。该模式通过抽象耦合实现发布-订阅机制,广泛应用于GUI事件处理、消息通知、数据监控等场景,具有良好的可扩展性和维护性。
327 8
|
设计模式 存储 供应链
前端必须掌握的设计模式——观察者模式
观察者模式(Observer Pattern)是一种行为型设计模式,实现了一种订阅机制。它包含两个角色:**观察者**(订阅消息、接收通知并执行操作)和**被观察者**(维护观察者列表、发送通知)。两者通过一对多的关系实现解耦,当被观察者状态改变时,会通知所有订阅的观察者。例如,商店老板作为被观察者,记录客户的需求并在商品到货时通知他们。前端应用中,如DOM事件注册、MutationObserver等也体现了这一模式。
|
8月前
|
设计模式 消息中间件 存储
【设计模式】【行为型模式】观察者模式(Observer)
一、入门 什么是观察者模式? 观察者模式(Observer Pattern)是一种行为设计模式,它定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会收到通知并自动更新。
382 9
|
10月前
|
设计模式 消息中间件 存储
设计模式:观察者模式
观察者模式属于行为型设计模式,用于建立对象间的一对多依赖关系。当主题(Subject)状态变化时,所有依赖的观察者(Observer)会自动收到通知并更新。
|
设计模式 消息中间件 搜索推荐
Java 设计模式——观察者模式:从优衣库不使用新疆棉事件看系统的动态响应
【11月更文挑战第17天】观察者模式是一种行为设计模式,定义了一对多的依赖关系,使多个观察者对象能直接监听并响应某一主题对象的状态变化。本文介绍了观察者模式的基本概念、商业系统中的应用实例,如优衣库事件中各相关方的动态响应,以及模式的优势和实际系统设计中的应用建议,包括事件驱动架构和消息队列的使用。
233 6
|
设计模式 监控 Java
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
Kotlin教程笔记(52) - 改良设计模式 - 观察者模式
111 1
|
8月前
|
设计模式 Java 数据库连接
【设计模式】【创建型模式】工厂方法模式(Factory Methods)
一、入门 什么是工厂方法模式? 工厂方法模式(Factory Method Pattern)是一种创建型设计模式,它定义了一个用于创建对象的接口,但由子类决定实例化哪个类。工厂方法模式使类的实例化延迟
236 16
|
8月前
|
设计模式 负载均衡 监控
并发设计模式实战系列(2):领导者/追随者模式
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发设计模式实战系列,第二章领导者/追随者(Leader/Followers)模式,废话不多说直接开始~
237 0
|
8月前
|
设计模式 监控 Java
并发设计模式实战系列(1):半同步/半异步模式
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发设计模式实战系列,第一章半同步/半异步(Half-Sync/Half-Async)模式,废话不多说直接开始~
221 0