什么是观察者模式?
观察者模式是一种对象行为型模式
观察者模式完美的将观察者和被观察的对象分开,它定义了对象建的一种一对多的依赖关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。
观察者模式有很多种表现形式,比如消息队列中经常听到的发布订阅(Subscribe)模式,MVC复合设计模式中的模型-视图(Model-View)模式,事件监听器的源-收听者(Listener)模式。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。
核心结构
- Subject。主题,代表了被观察的对象,在主题中定义一个观察者的集合,并提供添加、删除和通知观察者的方法,它可以是接口,也可以是抽象类。
- ConcreteSubject。具体主题,是主题的子类,包括一些需要变化的对象或数据,当它的状态发生改变时,会调用通知方法向各个已经注册的观察者发出通知。
- Observer。观察者,在具体主题发出通知后,观察者主要对通知作出适当的反应,一般的实现方式是接口,并定义相关的更新操作方法。
- ConcreteObserver。具体观察者,主要是作用是观察者的具体实现,它存储了相关状态。
类图展示
代码分析
构建高可用的服务,消息队列是目前必不可少的中间价之一,除了消息队列常用的发布订阅模式,还有最基本的生产者消费者模式,接下来我们就以生产者消费者模式发送消息为例来实现观察者模式。
首先,我们定义一个主题,也就是消息生产者:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/1/12 0012.
* 观察者模式——抽象主题
*/
public abstract class Producer {
protected List<Consumer> observerList = new ArrayList<Consumer>();
public void addObserver(Consumer consumer) {
observerList.add(consumer);
}
public void removeObserver(Consumer consumer) {
observerList.remove(consumer);
}
public abstract void produce();
}
接下来,我们定义一个抽象观察者,也就是消费者父类:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/1/12 0012.
* 观察者模式——抽象观察者
*/
public abstract class Consumer {
public abstract void send();
}
然后我们实现一个主题,也就是具体的消息生产对象:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/1/12 0012.
* 观察者模式——具体主题
*/
public class MessageProducer extends Producer {
@Override
public void produce() {
for (Consumer consumer : observerList) {
consumer.send();
}
}
}
同时实现两个观察者,便于测试,也就是具体的消息消费对象:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/1/12 0012.
* 观察者模式——具体观察者
*/
public class AndroidMessageConsumer extends Consumer {
@Override
public void send() {
System.out.println("Channel is sending the message");
}
}
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/1/12 0012.
* 观察者模式——具体观察者
*/
public class IOSMessageConsumer extends Consumer {
@Override
public void send() {
System.out.println("APNS is sending the message");
}
}
完活,接下来开始测试:
/**
* Created by <sunshine> mysunshinedreams@163.com on 2017/1/12 0012.
*/
public class ObserverTest {
public static void main(String[] args) {
observerTest();
}
private static void observerTest() {
try {
Consumer consumerOne = new AndroidMessageConsumer();
Consumer consumerTwo = new IOSMessageConsumer();
Producer producer = new MessageProducer();
producer.addObserver(consumerOne);
producer.addObserver(consumerTwo);
producer.produce();
producer.removeObserver(consumerTwo);
producer.produce();
} catch (Exception e) {
e.printStackTrace();
}
}
}
模式总结
优点
- 主题和观察者间建立了一个抽象的耦合,主题主需要维护一个观察者集合,并不需要关注观察者的业务实现,实现了一定程度上的代码解耦。
- 广播通信,降低了一对多系统的设计难度。
- 符合开闭原则,如果需要对观察者进行扩展,仅需实现观察者接口并添加到主题维护的观察者集合中即可。
- 代码实现更丰富,解放了具体观察者的实现限制,代码更多样化。
缺点
- 如果观察者集合过大,可能会影响系统性能。
- 如果观察者之间存在循环依赖,可能会造成循环调用导致内存溢出。
- 观察者不清楚主题为什么发生了变化,仅知道是否发生了变化。
试用场景
- 多个对象依赖于一个对象。
目前广泛应用于消息分发机制。