haohao

Android 设计模式之观察者模式

Markdown

2017 下半年,决定虐自己一把!

本篇开始将使用 Kotlin 代替 Java 来完成设计模式的示例,达到既学习了 Kotlin 语法,由复习了面向对象语言的设计模式。
本文是 Android 设计模式的第四篇,接下来会陆续推出整个常用的设计模式系列。

观察者模式

观察者模式 (Observer Pattern) , 顾名思义,定义了对象间的一种一对多的关系,当被观察者对象发生改变,与其依赖的观察者对象都会得到通知,因此又叫做发布-订阅模式 (Publish/Subscribe) 模式。

需要注意的是观察者模式是一种对象行为模式。

模式结构

  • Subject: 目标(被观察者)
  • ConcreteSubject: 具体目标(具体被观察者)
  • Observer:观察者
  • ConcreteObserver:具体观察者



盗图

模式实现

接下来在实例中我们以常见警匪电影中的坏蛋 (BadGuy) 作为 Observable ,以卧底警察 (Undercover)和普通警察 (PoliceMan)作为 Observer 。

Subject

Java 开发包中的 Observable 类,基本实现就是用一个 Vector 来接受所有的观察者,当被观察者的状态发生改变的时候,遍历 Vector 容器,通知每一个观察者。

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
public class Observable {
private boolean changed = false;
private Vector<Observer> obs;
/** Construct an Observable with zero Observers. */
public Observable() {
obs = new Vector<>();
}
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
public void notifyObservers() {
notifyObservers(null);
}
public void notifyObservers(Object arg) {
Object[] arrLocal;
synchronized (this) {
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}
for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}
public synchronized void deleteObservers() {
obs.removeAllElements();
}
protected synchronized void setChanged() {
changed = true;
}
protected synchronized void clearChanged() {
changed = false;
}
public synchronized boolean hasChanged() {
return changed;
}
public synchronized int countObservers() {
return obs.size();
}
}

ConcreteSubject

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class BadGuy : Observable() {
fun haveBreakfast() {
println("BadGuy: 开始吃饭了。。")
super.setChanged()
super.notifyObservers("坏蛋在吃饭")
}
fun commitCrime() {
println("BadGuy: 开始犯罪了。。")
super.setChanged()
super.notifyObservers("坏蛋在犯罪,建议立即采取行动")
}
}

Observer

1
2
3
4
public interface Observer {
void update(Observable o, Object arg);
}

ConcreteObserver

Undercover.kt 卧底警察

1
2
3
4
5
6
7
8
9
10
11
12
class UnderCover : Observer{
override fun update(o: Observable?, arg: Any?) {
println("卧底警察: 观察到疑犯活动了,赶紧报告队长!")
reportLeader(arg.toString())
}
fun reportLeader(message: String?) {
println("报告队长: $message \n")
}
}

PoliceMan.kt

1
2
3
4
5
6
7
8
9
10
class PoliceMan : Observer{
override fun update(o: Observable?, arg: Any?) {
println("警察: 观察到疑犯活动了,赶紧报告队长!")
reportLeader(arg.toString())
}
fun reportLeader(message: String?) {
println("报告队长: $message \n")
}
}

Sample

1
2
3
4
5
6
7
8
9
10
11
12
fun main(args: Array<String>) {
var badGuy = BadGuy()
val policeMan = PoliceMan()
val underCover = UnderCover()
badGuy.addObserver(policeMan)
badGuy.addObserver(underCover)
badGuy.haveBreakfast()
badGuy.commitCrime()
}

Running

1
2
3
4
5
6
7
8
9
10
11
12
13
14
BadGuy: 开始吃饭了。。
卧底警察: 观察到疑犯活动了,赶紧报告队长!
报告队长: 坏蛋在吃饭
警察: 观察到疑犯活动了,赶紧报告队长!
报告队长: 坏蛋在吃饭
BadGuy: 开始犯罪了。。
卧底警察: 观察到疑犯活动了,赶紧报告队长!
报告队长: 坏蛋在犯罪,建议立即采取行动
警察: 观察到疑犯活动了,赶紧报告队长!
报告队长: 坏蛋在犯罪,建议立即采取行动

观察者模式在面向对象语言编程中应用十分广泛,如著的 Reactive Extensions (RX) 函数库,其中 RxJava , RxAndroid 都是基于观察者模式。

在 Android 开发中,观察者模式也会被经常使用,如四大组件之一的 BroadcastReceiver 也是基于观察者模式。

观察者模式的优点和缺点

优点

  • 符合开闭原则
  • 可以实现表示层与数据逻辑层的分离
  • 观察者与被观察者之间的耦合是抽象的

缺点

  • 若一个目标对象有很多观察者,遍历通知每一观察将会变得耗时太长
  • 若目标对象与观察者对象存在循环依赖,可能会导致系统崩溃


联系我

Wechat ID

公众号

生活不止于眼前的苟且, 还有诗和远方的田野