观察者模式—— Observer
本系列文章中, State 模式的第一种实现方法 (switch 实现 state 转化 ) 将旋转门类 Door 作为 Observable 的子类,就采用了 Observer 模式。配套还应该实现 Observer 接口来支持对 Door 实例的观察。
记忆要点:
记住下面的UML class图.
一、 Observer 模式
观察者模式又叫做发布 - 订阅 (publish/subscribe) 模式、模型 - 视图 (Model/View) 模式、源 - 监听器 (Source/Listener) 模式或从属者 (Dependents) 模式。它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己 。
一个软件系统常常要求在某一个对象的状态发生变化的时候,某些其它的对象做出相应的改变。做到这一点的设计方案有很多,但是为了使系统能够易于复用,应该选择低耦合度的设计方案。减少对象之间的耦合有利于系统的复用,但是同时设计师需要使这些低耦合度的对象之间能够维持行动的协调一致,保证高度的协作( Collaboration )。观察者模式是满足这一要求的各种设计方案中最重要的一种。
类图如下:
二、代码实现(不使用 java.util.Observer 和 java.util.Observable )
调用方式:
public static void main(String[] args) { //1. 组装Observer模式 Observer obs1=new ConcreteObserver("obs1"); Observer obs2=new ConcreteObserver("obs2"); Observer obs3=new ConcreteObserver("obs3"); Subject subject=new Subject(); subject.attach(obs1); subject.attach(obs2); subject.attach(obs3); //2. 当subject状态改变时,会自动通知所有的观察者。 // 不用逐个去调用观察者的方法 subject.setState("新状态"); }
*****************************************************************
Subject:
import java.util.ArrayList; public class Subject { //维护Subject状态/属性 private String state; public void setState(String state) { this.state = state; notifyObservers(); } //提供Observer机制 private ArrayList<Observer> observers=new ArrayList<Observer>(); public void attach(Observer observer){ observers.add(observer); } public void detach(Observer observer){ observers.remove(observer); } public void notifyObservers(){ for(int i=0;i<observers.size();i++){ ((Observer)observers.get(i)).update(state); } } }
Observer:
public interface Observer { /** * Observer在Subject状态变化时被调用的方法 * @param message */ public void update(String message); }
ConcreteObsever:
public class ConcreteObserver implements Observer{ private String name=null; public ConcreteObserver(String name){ this.name=name; } /* Observer在Subject状态变化时被调用的方法 * @see observer.Observer#update() */ public void update(String message){ System.out.println("Observer["+name+"] received message["+message+"]"); } }
三、优点 / 缺点
优点 :
Observer 模式的优点是实现了表示层和数据逻辑层的分离,并定义了稳定的更新消息传递机制,类别清晰,并抽象了更新接口,使得可以有各种各样的表示层(观察者)。
1 )在被观察者和观察者之间建立了一个抽象的耦合。被观察者只知道观察者的一个集合,且只知道它们有一些公共的接口 ( 如 update()) 。因此两种角色的耦合度不高。
2 )支持广播通信。
缺点 :
每个观察者对象(外观对象)必须继承抽象出来的接口类,这样就造成了不方便。比如,有一个别人写的外观对象,并没有继承该抽象类,或者接口不对,我们又希望不修改该类直接使用它:虽然可以采用 Adaptor 模式一定程度上解决问题,但设计繁琐,增加出错几率。
1 )有很多直接或间接的观察者的话,通知所有的观察者很耗时。
2 )当观察者之间有循环依赖的话,当心被观察者触发它们之间的循环调用,导致系统崩溃 !
3 )如果对观察者的通知是通过另外的线程进行异步投递的话,系统必须保证投递是以自恰的方式进行的 ???