0%

设计模式-观察者模式

前言

设计模式将会用 Java 来演示。
这里仅仅是个比较浅层的理解,用于快速回顾,相当于笔记。
之所以记录下观察者模式,主要是因为此模式与我所探究的 java 委托 做比较

观察者模式是我认为最有意思的一个设计模式。

简介

当对象存在一对多的关系时,使用观察者模式(Observer Pattern)。
当一个对象被修改时,将回调更新依赖对象。
一种行为型模式

理解

简单来说首先系统存在一对多的关系(某个事物牵连使用者多个事物共享此事物的数据),当一个对象发生改变时,则会通知依赖此对象的其他对象,其他对象就会根据通知来做出更新。

是一种回调机制,当某件事做完后,就会通知依赖此对象的对象。

应用场景

其实十分广泛,在 Android 开发中就大量使用到 Observer 来传递数据,更新数据。除此以外,比如按键事件的监听也是一种回调机制。

一个抽象模型有两个方面,其中一个方面依赖于另一方面。将这些方面封装在独立对象中使其可以肚子改变和复用。

一个对象的改变会导致一个或多个对象发生改变,可以降低对象间的耦合。

一个对象必须通知另外其他对象,且并不知道这些对象是谁

需要在系统中创建一个触发链,A对象行为影响B,B影响C,… 可使用观察者模式。

实现

一个简单的数据转换的案例
来自于菜鸟教程——观察者模式 的案例

UML

1

  • Subject 是回调通知的关键,其包含状态,观察者集合 的属性,更新通知观察者的方法
  • Observer 观察者抽象类,属性有 Subject ,主要是与观察者进行数据间的通信
  • 需要作为观察者的子类 继承 Observer
  • 主函数,改变 subject 的状态,将会回调通知观察者进行更新

代码

选自[菜鸟教程——观察者模式] 1 的代码案例

  1. 创建 Subject类,其实是主要的回调的类对象,作用是有自己的逻辑,同时也能通知观察者来更新。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import java.util.ArrayList;
import java.util.List;

public class Subject {
// 观察者数组,其实为了逐个通知
private List<Observer> observers
= new ArrayList<Observer>();
// 状态,也可根据自身开发来更改,这个属性是特有属性,并不是必要的
private int state;

public int getState() {
return state;
}

public void setState(int state) {
this.state = state;
notifyAllObservers();
}

// 加入观察者,会在观察者被创建时,将其加入集合中
public void attach(Observer observer){
observers.add(observer);
}

// 通知方法,通知每个观察者更新
public void notifyAllObservers(){
for (Observer observer : observers) {
observer.update();
}
}
}
  1. Observer 抽象类
1
2
3
4
public abstract class Observer {
protected Subject subject;
public abstract void update();
}
  1. 观察者子类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 数字二进制转换
public class BinaryObserver extends Observer{

// 添加到集合中
public BinaryObserver(Subject subject){
this.subject = subject;
this.subject.attach(this);
}

@Override
public void update() {
System.out.println( "Binary String: "
+ Integer.toBinaryString( subject.getState() ) );
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 数字八进制转换
public class OctalObserver extends Observer{

public OctalObserver(Subject subject){
this.subject = subject;
this.subject.attach(this);
}

@Override
public void update() {
System.out.println( "Octal String: "
+ Integer.toOctalString( subject.getState() ) );
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 数字十六进制转换
public class HexaObserver extends Observer{

public HexaObserver(Subject subject){
this.subject = subject;
this.subject.attach(this);
}

@Override
public void update() {
System.out.println( "Hex String: "
+ Integer.toHexString( subject.getState() ).toUpperCase() );
}
}
  1. 主函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ObserverPatternDemo {
public static void main(String[] args) {
Subject subject = new Subject();

new HexaObserver(subject);
new OctalObserver(subject);
new BinaryObserver(subject);

System.out.println("First state change: 15");
subject.setState(15);
System.out.println("Second state change: 10");
subject.setState(10);
}
}
  1. 结果
1
2
3
4
5
6
7
8
First state change: 15
Hex String: F
Octal String: 17
Binary String: 1111
Second state change: 10
Hex String: A
Octal String: 12
Binary String: 1010

优点/缺点

优点

  1. 观察者和被观察者抽象耦合
  2. 建立了一套触发机制

缺点

  1. 如果被观察对象有很多直接或间接的观察者,要遍历通知所有观察者花费时间长
  2. 如果在观察者和观察目标间有循环依赖的话,观察目标会触发它们之间进行循环调用,会导致系统崩溃。
  3. 观察者模式没有相应机制让观察者知道所观察的目标对象是如何变化的,仅仅知道观察目标发生了变化。

注意

  1. Java 中已经有了对观察者模式支持的类(以后有机会,详细探讨)。
  2. 避免循环引用。
  3. 如果顺序执行,某一观察者会导致系统卡壳,一般采用异步方式。

参考

菜鸟教程–观察者模式