观察者模式是用于解耦的,把不同功能的类,而又对某一共同事件或者消息感兴趣解耦开来,使双方互不知道对方。常规的实现是通过接口的方式来把需要关注的消息封装起来,双方各自实现接口即可。
理解观察者模式
什么是观察者模式
观察者模式Observer pattern用于解耦消息发布或者状态发布的,对象之间有消息依赖的一种设计模式。消息发布者,或者说被关注者称之为主体(Subject),它会不定时的更新消息和状态,希望接收到消息和状态变化的称为观察者(Observer)。用接口来隔离主题对象(被关注者)和观察者,观察者被动接收来自主题的变化,然后更新自己的状态。
通常也被称作为发布-订阅者模式因为它与生活中的报纸杂志订阅非常的类似,用户(Subscriber)向发行商(Publisher)订阅,当有新的期刊来了时,发行商会邮寄给用户。发行商称之为Subject或者Publisher,用户称之为Observer或者Subscriber,添加订阅称作Subscription,邮寄新期刊称之为notify。
Subject持有一个Observer的列表,提供三个接口:添加订阅(attach或者addObserver),取消订阅detach或者removeObserver)和通知更新(notify),Observer则有一个更新(update)。
订阅 关系建立后,当有新的数据或者状态需要更新时,Subject就会调用notify接口来实现状态的发布。
观察者模式的示例
对于大部分编程语言来说都提供了观察者模式的接口,比如Java中就可以直接用java.util.Observable和java.util.Observer来实现。
java
import java.util.Observable;
import java.util.Observer;
import java.util.Random;
public class TestDriver {
public static void main(String[] args) {
final MusicTeacher teacher = new MusicTeacher();
final Student tommy = new Student("Tommy", findViewById(R.id.tommy));
final Student jimmy = new Student("Jimmy", findViewById(R.id.jimmy));
final Student george = new Student("George", findViewById(R.id.george));
teacher.addObserver(tommy);
teacher.addObserver(jimmy);
teacher.addObserver(george);
teacher.singWithMe();
teacher.singWithMe();
teacher.singWithMe();
}
}
class MusicTeacher extends Observable {
private static final String[] songs = {
"\tTwinkle twinkle little star,\n\tHow I wonder what you are.",
"\tJohnny Johnny?\n\tYes papa.\n\tEating sugar?\n\tNo papa.",
"\tHumpty dumpty sat on wall,\n\tHumpty dumpty had a great fall.",
"\tOne two three four five,\n\tOnce I caught a fish alive."
};
private Random random;
public MusicTeacher() {
random = new Random(System.currentTimeMillis());
}
public void singWithMe() {
setChanged();
notifyObservers(songs[random.nextInt(songs.length)]);
}
}
class Student implements Observer {
private final String name;
public Student(String name) {
this.name = name;
}
@Override
public void update(Observable observable, Object o) {
System.out.println(name + ":\n" + o.toString());
}
}
常规的实现是这样的,在代码层面有直接的依赖,也就是说Observable与Observer相互知道对方的存在,且代码上面有直接的编译依赖关系。并且一般也都是同步的,状态变化 后Subject会直接发出通知,以更新Observer。
什么时候用观察者模式
观察者模式的特点是『一对多』,主体只有一个,向多个观察者发布状态更新,这是它最主要的特点。另外就是,它最主要的作用是解耦 这种『一对多』状态更新关系。所以,当需要解决这种『一对多』状态更新的问题时就可以使用观察者模式。
厘清问题,找到主体Subject,再找到Observer,然后分别实现对应的接口即可。
发布-订阅模式
随着软件越来越复杂,比如组件的出现,多中间件的出现,远程(服务器客户端),并发和多线程多进程的出现,使得观察者模式也有了新的样式,比如Subject和Observer可以不会有直接依赖关系,或者都依赖于一个中间组件,比如一些Event-Bus系统,以及消息的更新与通知都是异步的。 这时就是出现了发布-订阅者模式(Publish-Subscrib pattern)。 向外发布消息的叫Publisher,它与Observable类似,但最重要的区别在于,Publisher并不知道Subscriber的存在,它是直接像一个第三方的消息队列,或者叫做消息平台,发布消息。而Subscriber,也不知道Publisher的存在,是直接向消息队列或者消息平台订阅。
它的特点是:
- 组件间,甚至是不同的应用之间,不同的端之间的消息发布模型。
- 都是异步的,就说是发布者是往消息队列发消息,然后就算发布完成了。订阅者是从消息队列拿消息。Publisher与Subscriber之间并无同步关系。一个消息发布出去,接收时间不确定。
- 对应该关系自由,可以多对多,也可以多对一或者一对多。
- 支持并发。
安卓里面非常著名的EventBus就是这一模式的经典实现。以及Linux世界里的dbus也是这种。
关于观察者模式与发布者模式区别可以看这篇文章。
生产者消费者问题
再有一个比较类似的就是生产者和消费者问题(Producer consumer problem)主要是涉及多线程和同步问题。
参考资料
- LabVIEW之生产者/消费者架构
- How to: Implement a producer-consumer dataflow pattern
- The Producer Consumer Pattern
- Observer Design Pattern
- Design Patterns - Observer Pattern
- Observer Pattern | Set 1 (Introduction)
- Observer
- 设计模式(五)观察者模式
- The Observer Pattern
- Publisher-Subscriber pattern
- Publisher-Subscriber
- What is the Producer-Consumer problem?
- Producer-Consumer problem
欢迎搜索并关注 公众号「稀有猿诉」 获取更多的优质文章!
保护原创,请勿转载!