在过去的一年中,已经关注过一段设计模式相关的问题,也经常会使用到诸如单例模式,工厂模式,代理模式等进行开发,一直没有系统的对此进行系统的学习,买了的《设计模式之禅》纸质书也一直放在一边。近期报名了炼数的java网络服务器程序开发课程,第一课就用到了观察者模式,于是拿起来复习了一下。目前,对于观察者模式的认识仅仅局限于秦小波的《设计模式之禅》这本书中介绍的例子,以后想到什么相关的就在这里添加。下面的每个标题都是我个人对观察者模式的一些理解

1.为什么会采用观察者模式?

过去1年中,写过很多类似于下面这种场景的程序。

一个生产者,多个消费者,生产者产生Message,多个消费者都要对同一个Message进行处理,注意这里是同一个Message,通常我们会采用如下两种思路来写这个程序,假设我们这里用Java进行编写。

写法1:

定义生产者类(Producer),多个消费者类(Cusumer),然后再定一个业务逻辑处理类(ProcessThread),其中ProcessThread包含Producer和Cusumer的对象,然后继承自Thread类,java的线程如此简单,然后实现run函数,在run函数中,

while(true){

//当生产者产生一条Message

//马上调用消息者对象对Message进行依次处理

}

这个程序的缺点在于,while(true){   //业务逻辑}     CPU一直处于100%运行状态,IDE也会处于假死状态。即时我们在while(true)循环中增加休眠功能,但一方面休眠产生中断,唤醒所耗费的性能以及休眠导致的消息无法及时进行处理。稍微有点开发经验的程序员都会避免这种写法。但事实上,我在一段时间曾经这么干过,并且目前维护的程序中依然有这样的程序。

写法2:

定义生产者类(Producer),多个消费者类(Cusumer),在生产者类中包含消费者对象,当生产这产生Message时,马上调用消费者对象进行处理。

这种程序看起来解决了写法1的运行效率问题,但事实上我们的程序总是在随着客户的需求不断的改变,各种各样的需求就会写各种各样的消费者,我们每次进行升级都要对生产者类,消费者类程序进行改动,扩展。很明显,这样的程序耦合性导致程序的扩展性,可维护性大大降低。

于是,观察者模式在这里就可以应用了。

定义一个生产者(被观察者),它的功能包括增加消费者(观察者),删除消费者,通知消费者对Message进行消费的3个功能。定义一个消费者(观察者),然后在消费者内编写业务逻辑,事实上,不同的逻辑的消费者编写不同的代码,所有的消费者实现同一接口,然后在内部对不同的业务逻辑进行实现即可,然后添加到程序即可。这样实际的应用流程就可以如下表示了:

1.创建生产者(被观察者)

2.创建消费者(观察者,可能为1个或者多个)

3.将消费者(观察者)添加到生产者(被观察者)中

4.当生产者产生消息时,通知所有的消费者进行处理。

这种写法的优点在于:

生产者(被观察者)的职责很简单,就是定义谁能够观察,谁不能观察。观察者可以保存到一个list或者vector中。

而消费者(观察者,一般是一个接口),凡是实现该接口的类都具体的消费者(观察者)。扩展应用逻辑时,只需要实现该接口即可,然后由生产者来控制谁可以观察。谁不可以观察。

2.观察者模式的优点:

2.1 观察者与被观察者之间是抽象耦合的,系统扩展非常方便

2.2 建立了一套触发机制,这样就可以将单一指责的类串联到一起,形成了一套触发链。

3.观察者模式的缺点:

观察者模式的缺点在于开发效率和运行效率的问题,一个生产者,多个消费者消费同一条消息,调试复杂,java中消息的通知是顺序执行的,一旦一个消费者执行卡壳,整个生产者的逻辑也会卡壳。当然,采用异步设计也可以解决。

另外,如果多级触发也是在逻辑上难以理顺的

4.观察者模式的应用场景:

4.1 事件多级触发场景,显而易见,就是触发链的设计

4.2 跨系统的消费交换场景,比如消息队列中的同一条消息要经过不同系统的处理。

5. 观察者模式的注意事项:

5.1 注意广播链,也就是多级触发的问题,尽可能的保证消息最多转发1次,也就是同一条消息传递2次,如果传递2次以上逻辑就很难处理。

5.2 异步处理的问题,要考虑线程安全和队列的问题。

6. Java开发中应用观察者模式:

java中提供java.util.Observable这个父类和java.util.Observer接口,我们在使用时只需要继承或者实现该接口就可以了。

7.项目中的一些问题:

7.1 观察者和被观察者之间的消息传输,一般是Bean进行传输,由被观察者生成,观察者消费,这里如果是跨网络传输,可以考虑使用xml或者google的protobuf封装,优点是可以跨语言,跨平台,当然还有很多持久化的方法可以借鉴。

7.2 观察者的响应方式,前面提到了观察者的响应是按顺序的,一旦其中一个卡壳,整个逻辑都会卡壳,这里要着重设计的是观察者的快速响应,常用的两种方式,一是多线程技术,每个请求都创建线程进行处理,二是缓冲技术,缓冲可以采用缓冲区,消息队列等方式,这里的解决方案得根据实际的业务情景来选择。

7.3 被观察者尽量自己来控制哪些动作可以通知观察者,哪些不可以,这个可以通过增加一个参数来控制即可。

8.总结:

其实,观察者模式就是发布/订阅者模式,很多消息队列都支持这种模式的应用,比如注明的ZeroMQ三大典型的应用之一就是这种模式。在实际应用中这种模式非常常见,比如交警卡口系统中一条卡口过车数据,既要在套牌分析中进行,又要进行首次入城分析,还要快速的将数据存储到数据库中。这里,过车数据就是被观察者,套牌分析模块,首次入城分析模块,数据存储模块就是观察者。事实上,我觉得,在大部分同一条消息被多个消费者消费的场景都可以考虑采取这种模式来实现。

设计模式-观察者模式
Tagged on:     

发表评论

电子邮件地址不会被公开。 必填项已用*标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.