15-观察者模式

观察者模式

分析

交通信号灯与汽车示意图

image-20221219202301412

联动:两类对象之间的变化的联动

  • 一对一的联动

  • 一对多的联动

分析
  • 交通信号灯\leftrightarrow观察目标

  • 汽车(汽车驾驶员)\leftrightarrow观察者

image-20221219202439035

一对多关系

  • 一个观察目标

  • 多个观察者

  1. 软件系统:一个对象的状态或行为的变化将导致其他对象的状态或行为也发生改变,它们之间将产生联动

  2. 观察者模式:

    • 定义了对象之间一种一对多的依赖关系,让一个对象的改变能够影响其他对象

    • 发生改变的对象称为观察目标,被通知的对象称为观察者

    • 一个观察目标可以对应多个观察者

观察者模式的定义

image-20221219202955876

对象行为型模式

别名
  • 发布-订阅(Publish/Subscribe)模式

    • 比如:用户关注同一个公众号
  • 模型-视图(Model/View)模式

    • Model(观察目标)中的数据改变会导致View也发生变化(观察者)
  • 源-监听器(Source/Listener)模式

    • 事件源(观察目标)
    • 监听器(观察者)
  • 从属者(Dependents)模式

观察者模式结构

image-20221219203409264

以上类图中两个部分不必要:

  1. 具体观察目标(ConcreteSubject)不必要

  2. 具体观察者反向调用ConcreteSubject的关联关系不必要

对于不同的观察者子类的update方法实现不同

最简单的观察者模式不需要ConcreteSubject类,即可实现一对多的关系!

观察者在某些时候需要反向调用具体观察目标(ConcreteSubject)的状态数据等:

image-20221219204003009

观察者模式包含以下4个角色:
  • Subject(目标)

  • ConcreteSubject(具体目标)

  • Observer(观察者)

  • ConcreteObserver(具体观察者)

典型的抽象目标类代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import java.util.*;
public abstract class Subject {
//定义一个观察者集合用于存储所有观察者对象
protected ArrayList<Observer> observers = new ArrayList<Observer>();

//注册方法,用于向观察者集合中增加一个观察者
public void attach(Observer observer) {
observers.add(observer);
}

//注销方法,用于在观察者集合中删除一个观察者
public void detach(Observer observer) {
observers.remove(observer);
}

//声明抽象通知方法
public abstract void notify();
}
典型的具体目标类代码
1
2
3
4
5
6
7
8
9
public class ConcreteSubject extends Subject {
//实现通知方法
public void notify() {
//遍历观察者集合,调用每一个观察者的响应方法
for(Object obs:observers) {
((Observer)obs).update();
}
}
}
典型的抽象观察者代码
1
2
3
4
public interface Observer {
//声明响应方法
public void update();
}
典型的具体观察者代码
1
2
3
4
5
6
public class ConcreteObserver implements Observer {
//实现响应方法
public void update() {
//具体响应代码
}
}
说明:
  • 有时候在具体观察者类ConcreteObserver中需要使用到具体目标类ConcreteSubject中的状态(属性),会存在关联或依赖关系

  • 如果在具体层之间具有关联关系,系统的扩展性将受到一定的影响,增加新的具体目标类有时候需要修改原有观察者的代码,在一定程度上违背了开闭原则但是如果原有观察者类无须关联新增的具体目标,则系统扩展性不受影响

典型的客户端代码片段
1
2
3
4
5
6
……
Subject subject = new ConcreteSubject();
Observer observer = new ConcreteObserver();
subject.attach(observer); //注册观察者
subject.notify();
……
实例类图

image-20221221191510214

image-20221221191543280

image-20221221191551207

广播通信:一对多

以上实例实现了一次一对一的联动,一次一对多的联动

(1) AllyControlCenter:指挥部(战队控制中心)类,充当抽象目标类

(2) ConcreteAllyControlCenter:具体指挥部类,充当具体目标类

(3) Observer:抽象观察者类

(4) Player:战队成员类,充当具体观察者类

(5) Client:客户端测试类

image-20221221191936537

JDK对观察者模式的支持

java.util.Observer以及java.util.Observable

image-20221221192633066

Observable的Vector类型属性便于实现一对多的操作。

观察者模式与Java事件处理

  1. 事件源对象充当观察目标角色,事件监听器充当抽象观察者角色,事件处理对象充当具体观察者角色

  2. 如果事件源对象的某个事件触发,则调用事件处理对象中的事件处理程序来对事件进行处理

image-20221221192901167

  • 事件源(Event Source) :Subject

    • 例如:JButton,addActionListener():注册方法;fireXXX(): 通知方法
  • 事件监听器(Event Listener):Observer

    • 例如:ActionListener,actionPerformed():响应方法
  • 事件处理类(Event Handling Class):ConcreteObserver

    • 例如:LoginHandling:实现ActionListener接口

image-20221221193014582

观察者模式与MVC

MVC(Model-View-Controller)架构
  • 模型(Model),视图(View)和控制器(Controller)

  • 模型可对应于观察者模式中的观察目标,而视图对应于观察者,控制器可充当两者之间的中介者

  • 当模型层的数据发生改变时,视图层将自动改变其显示内容

image-20221221193704264

模型层的数据就是观察目标,View就是观察者。当数据改变时,View中的图标也会跟随变化。

模式优点

  • 可以实现表示层和数据逻辑层的分离

  • 在观察目标和观察者之间建立一个抽象的耦合

    • 观察目标不一定需要抽象层,但观察者必须有抽象层
  • 支持广播通信简化了一对多系统设计的难度

  • 符合开闭原则,增加新的具体观察者无须修改原有系统代码,在具体观察者与观察目标之间不存在关联关系的情况下增加新的观察目标也很方便

    • 建立在具体层的关联关系可能会破坏开闭原则
    • image-20221221194310474

模式缺点

  • 将所有的观察者都通知到会花费很多时间

  • 如果存在循环依赖时可能导致系统崩溃

  • 没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而只是知道观察目标发生了变化

    • 形象来说:老鼠知道猫在叫,所以老鼠要跑,但是老鼠不知道猫为什么叫

模式适用环境

  • 一个抽象模型有两个方面,其中一个方面依赖于另一个方面,将这两个方面封装在独立的对象中使它们可以各自独立地改变和复用

  • 一个对象的改变将导致一个或多个其他对象发生改变,且并不知道具体有多少对象将发生改变,也不知道这些对象是谁

    • 一对一多的广播机制(一对多的联动)
  • 需要在系统中创建一个触发链

    • image-20221221194810325
    • 中间的对象将会即是观察者又是观察目标
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2023-2024 Guijie Wang
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信