前言
观察者模式是属于设计模式中的行为型模式,所谓<code>行为型</code>就是指对象的动作发生改变,比如方法以及状态。那么观察者模式是一种什么模式呢?说白了,观察者模式解决的一对多的依赖关系,当一个对象的状态发生改变的时候,其他依赖此对象的对象会得到通知并且做出相应的改变。但从定义上还是很难理解。我们可以从一个简单的例子中更深地去体会观察者模式。
某公司的两名职员在主管离开办公室后,一个在看股票,一个在玩游戏。公司有一个前台,该两名职员让前台当主管回来的时候通知他们不让主管看到他们在干其他的事。
根据上述场景,下面是我写出的第一版代码:
最后程序的运行结果如下:
我在程序使用的都是抽象类,抽象类是对类的抽象,类是对对象抽象。但是如果考虑到通知者有可能是完全不相关的对象,使用抽象类就不是很合理了,于是可以换成接口,接口是对类行为的抽象,通知者的核心职责就是告诉观察者具体的通知,其他的都不是最重要的。下面对代码进行进一步的的优化:
最后的测试结果是:
从以上两个测试结果可以发现,只要notifyer的message属性发生改变,其所管辖的观察者的动作也发生了更新。注意到在测试代码中没有将第三个对象添加进来,这样当notifyer的状态发生改变其动作不会发生更新。这样只有前两个对象发生了动作的更新。也就是说notifyer这个对象的状态发生改变导致了其他两个对象的改变。而观察者模式也正是在这种情况下使用的。当一个对象的状态改变导致其他对象的状态也发生改变,而且不知道有多少具体的对象的状态要发生改变的时候,应该使用观察者模式。观察者模式有两个关键对象subject(对应上面代码中的notifyer和inotify对象)和observer(对应上面的employee对象)。subject状态的改变会导致observer对象的状态的改变一个subject对象可以吧状态的改变通知给任意数目的观察者对象。一个subject不需要知道具体的观察者,一个观察者也不需要知道其他观察者是否存在。实际上观察者模式主要是为了解耦(实际上23种设计模式中都体现了这一点,只不过不同的设计模式体现程度不同罢了),使得对象之间不依赖具体而是依赖抽象。这样设计的好处对具体的大修改不会影响其他依赖抽象的类,使得类之间的耦合度降低。
可以发现,在上面我们的代码中,具体的subject是依赖observer对象的,这样的依赖会不会影响呢?答案是肯定的。
虽然subject和observer都是抽象的,但是难保在系统中会一直存在这样抽象的observer,所以这样的依赖已经最大程度减少了程序之间的耦合,但在这种情况下还是存在问题的。那么还没有其他的方法解决这种耦合呢?有。我们可以采用一种委托的事件机制完成进一步的解耦。事件委托可以将委托者的方法可以事件中去执行,事件委托仅仅需要的是要执行方法的对象、方法以及参数列表,这样事件委托对象就可以根据这三个参数执行制定对象的指定方法,从直观上理解,有点象代理,但不同于代理,由于在java中没有现成的事件委托模型可以使用,可以实现一个自己的事件委托处理器。实现之后,我们在subject中引入这个事件委托处理器,并添加相应的事件响应方法,而observer对象不需要做任何改变。具体事件委托处理器的代码可以参考我的github上的源码。
最后对观察者模式做一个简单的总结:
观察者模式主要适用于一个对象的改变会导致其他对象状态的改变的情况
使用抽象降低需要关联对象的耦合,不依赖具体而是依赖抽象
观察者模式的不足在于如果observer对象的不再存在将对系统产生重大影响