设计模式之禅——观察者模式

引:被观察者做出动作了,然后通知观察者做出反应。观察者模式就是这么简单!

定义

观察者模式又称发布订阅模式。

定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有它依赖的对象都会得到通知并被自动更新。行为类

下面是它的通用类图:

observer

下面简单介绍一下类图中的几个角色:

  1. Subject被观察者:定义观察者必须实现的职责,它必须能够动态地增加、取消观察者。管理观察者并通知观察者。
  2. Observer观察者:观察者接受到消息后,即进行update操作,对接收的信息进行处理。

下面是它的通用源代码:

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
// 被观察者
public abstract class Subject {
// 定义一个观察者数组
private Vector<Observer> observerVector = new Vector<Observer>();
// 增加一个观察者
public void addObserver(Observer o) {
this.observerVector.add(o);
}
// 删除一个观察者
public void deleteObserver(Observer 0) {
this.observerVector.remove(o);
}
// 通知所有观察者
public void notifyObservers() {
for (Observer o : this.observerVector) {
o.update();
}
}
}

// 具体被观察者
public class ConcreteSubject extends Subject {
// 具体的业务
public void doSomething() {
// do somthing
super.notifyObservers();
}
}

// 观察者
public interface Observer {
// 更新方法
public void update();
}

// 具体观察者
public class ConcreteObserver implements Observer {
// 实现更新方法
public void updatea(){
System.out.println("接到消息,并进行处理");
}
}

// 场景类
public class Client {
public static void main(String[] args) {
// 场景一个被观察者
ConcreteSubject subject = new ConcreteSubject();
// 定义一个观察者
Observer obs = new ConcreteObserver();
// 观察者观察被观察者
subject.addObserver(obs);
// 观察者开始活动了
subject.doSomething();
}
}

应用

优点

  1. 观察者和被观察者之间是抽象耦合的,不管是增加观察者都非常容易扩展。
  2. 建立一套触发机制。容易在单一职责下构建一条触发链。

缺点

观察者模式需要考虑一下开发效率和运行效率问题,一个被观察者,多个观察者,开发和调试就会比较复杂,而且在Java中消息的通知默认是顺序执行的,一个观察者卡壳,会影响整体的执行效率。在这种情况下,一般考虑采用异步的方式。

使用场景

  1. 关联行为场景。这种关联行为时可以拆分的。
  2. 事件多级触发场景。
  3. 跨系统的消息交换场景,如消息队列的处理机制。

注意事项

  1. 广播链。在一个观察者模式中最多出现一个对象既是观察者又是被观察者,也就是说消息最多被转发一次。(和责任链的区别在于广播链在消息传播过程中消息是可变的)
  2. 异步处理问题。如果观察者比较多,处理时间长,我们就需要用异步。异步处理需要考虑到线程安全和队列问题。

扩展

Java世界中的观察者模式

在JDK中已经提供了java.util.Observable实现类(被观察者)以及java.util.Observer接口(观察者)。大家要记住在java的世界里横行时,多看看API,有很大的帮助,很多东西Java已经帮我们设计了一个良好的框架。

项目中真实的观察者模式

在系统设计中会对观察者模式进行改造或改装,主要在以下3个方面:

  1. 观察者和被观察者之间的消息沟通

    被观察者状态改变会触发观察者的一个行为,同时会传递一个消息给观察者,这是正确地,但是在实际中一般的做法是:观察者中update方法会接受两个参数,一个是被观察者,一个是DTO(数据传输对象),DTO一般是一个纯洁的JavaBean,由被观察者生成,由观察者消费。

  2. 观察者响应方式

    为了解决观察者的快速响应有以下两个办法:

    • 采用多线程技术
    • 缓存技术(同步架构)
  3. 被观察者尽量自己做主

    被观察者的状态改变不一定要通知观察者,所以doSomething方法可以被重载,增加一个doSomething(boolean isNotifyObs)方法,决定是否通知观察者,而不是在消息到达观察和才判断是否要消费。

订阅发布模型

顾名思义就是消息的发布者发布一个消息,然后利用消息队列通知订阅者做出反应。这相当于观察者模式的升级版。

最佳实践

观察者模式在实际项目中和生活中非常常见,如下面的例子:

  1. 文件系统:在一个目录下新建立一个文件,这个动作会同时通知目录管理器增加该目录。文件是一个被观察者,目录管理器是一个被观察者。
  2. 广播收音机:电台在广播,收音机在收听。电台是一个被观察者,收音机是一个被观察者。

    参考

  3. 《设计模式之禅》