Head First 设计模式学习——观察者模式

来源:互联网 发布:pc端软件下载 编辑:程序博客网 时间:2024/06/06 00:24

设计模式是进阶高级开发的必经之路。掌握设计模式,才能提升编码能力,设计出可复用、可扩展、可维护的软件系统。了解设计模式,才能更好理解开源类库的实现原理,解决问题。
观察者模式(Observer Pattern)是《Head First 设计模式》介绍的第二个模式。本文将做介绍,并介绍此模式在JDK中的应用。

定义

观察者模式定义了对象之间的一(被观察者)对多(观察者)依赖,这样一来,当一个对象(被观察者)改变状态时,它的所有依赖者(观察者)都会收到通知并自动更新。

应用场景举例

  • 用户订阅报社报纸。当报社印刷新报纸(状态改变),向所有订阅用户投递报纸(推送消息)。用户可随时取消、加入订阅。
  • 火车站的车次显示屏,显示车次到达发车信息。当火车数据更改时,每个显示屏都要及时更新数据。等等

分析

上述两个例子中,可以抽象出一对多的关系,比如报社对应多个用户,火车数据对应多个显示屏。用户、显示屏等是观察者,报社、火车数据是被观察者。而且观察者的数量动态变化的。有人退出,有人加入,类型不固定(有公司订阅报纸,有微信、微博发布火车时刻信息)。
如果用java实现这样的功能。自然的,可以抽象出被观察者类、观察者类。

观察者可能会观察多个数据源,一个数据源也会被不同类型的观察者关注。若在类中指定观察者、被观察者具体类型(比如报社——人,火车数据——显示屏),以后报社新增公司客户(新增观察者),火车数据新增广播平台(新增观察者),一个客户订阅另一本杂志(新增被观察者),我们就得去修改代码,糟透了。

此处,一个新的设计原则:为了交互对象之间松设计而努力诞生了。

我们应该把观察者、被观察者抽象成抽象类或者接口,定义公共的方法。让以后的观察者、被观察者实现这些接口或抽象类即可。考虑到另一个原则:针对接口编程,我们采用接口抽象。

为了能及时追踪被观察者的变化。一种方式是观察者无间断盯着被观察者,不断的问:··你到底变没变?你到底变没变?

 //观察者 while(true){    //问被观察者:你到底变没变    if(观察者.hasChanged()){    //do something    }}

很明显,这种方式,彼此压力都很大,不是个好设计。

另一种方式,就是当被观察者发生改变时,主动的通知观察者(调用观察者某个方法),观察者随机做出反应:

//被观察者通知观察者notifyObservers(){    //依次通知,也可以设计成单个通知    for(){        观察者.update("喂,我变帅啦");    }}//回执result(观察者 观察者1,String info){    System.out.println(观察者1.class.getName()+"发来消息:"+info)}-------------------------------------------//观察者update(String info){    System.out.println("收到消息,被观察者:"+info);    //甚至可以设置个回执,告诉被观察者,你的消息我收到了    //传入观察者自己,好让被观察者知道谁给他发的回执    被观察者.result(观察者,"我收到你的消息了");}

这才是我们想要的。再加上新增、删除观察者功能,我们基本上就实现了观察者模式设计了。

代码

根据面向接口编程原则,把观察者、被观察者抽象成接口:

//被观察者Observered接口public interface Observered {    //新增一个观察者    void addObserver(Observer observer);    //删除某个观察者    void removeObserver(Observer observer);    //通知所有观察者    void notifyObserver();}//-----------------------------------------//观察者Observer接口public interface Observer {    //被观察者调用。    //@param observered 被观察者(有可能当前观察者关注了多个数据源)    //@param obj 传入的数据。自定义类型,此处用Object    void update(Observered observered,Object obj );}

接下来就是具体的实现类。此处我们安排三个观察者,两个被观察者。场景:
AboyBboy在淘宝上买了东西,淘宝Taobao需要推送发货信息给AboyBboyAboyCgirl关注了一个公众号WeChatPublicSignal(姑且这么叫吧),公众号会推送文章给这俩人。
首先两个被观察者:TaobaoWeChatPublicSignal

class Taobao implements Observered{    //用LinkedList<E>或其他结构    List<Observer> observerList = new ArrayList<Observer>();    @Override    public void addObserver(Observer observer) {        //添加一个观察者        observerList.add(observer);    }    @Override    public void removeObserver(Observer observer) {        observerList.remove(observer);  //移除一个观察者       }    @Override    public void notifyObserver() {        //遍历,通知所有观察者并发送消息        for (Observer observer : observerList) {            System.out.println("Taobao说:我正在发数据给"+observer.getSimpleName().getName());            //此处的数据参数可以灵活设计            observer.update(this, "你买的娃娃已经发货啦___");        }    }}class Taobao implements Observered{//其他代码同Taobao,略,只改动发送的数据    observer.update(this, "咪蒙说:外国人那么大,我想去看看");}

三个观察者Aboy、Bboy和Cgirl

//实现观察者接口class Aboy implements Observer{    @Override    public void update(Observered observered, Object obj) {        System.out.println("Aboy------说:我接收到--"+observered.getClass().getSimpleName()+"--发来数据:  "+obj);         }}//Bboy、Cgril同Aboy,略

测试:

    public static void main(String[] args) {        //实例化观察者        Observer aboy = new Aboy();        Observer bboy = new Bboy();        Observer cgirl= new Cgirl();        Observered taobao = new Taobao();//被观察者Taobao        //添加观察者        taobao.addObserver(aboy);        taobao.addObserver(bboy);        //通知观察者        taobao.notifyObserver();        //下同        Observered wechat = new WeChatPublicSignal();        wechat.addObserver(aboy);        wechat.addObserver(cgirl);        wechat.notifyObserver();    }

控制台输出:

Taobao----说:我正在发数据给--AboyAboy------说:我接收到--Taobao--发来数据:  你买的娃娃已经发货啦___Taobao----说:我正在发数据给--BboyBboy------说:我接收到--Taobao--发来数据:  你买的娃娃已经发货啦___WeChatPublicSignal说:我正在发数据给AboyAboy------说:我接收到--WeChatPublicSignal--发来数据:  咪蒙说:外国人那么大,我想去看看WeChatPublicSignal说:我正在发数据给CgirlCgirl-----说:我接收到--WeChatPublicSignal--发来数据:  咪蒙说:外国人那么大,我想去看看

结果符合设计。

JDK中的应用

观察者模式在JDK中有实现。java.util.Observer就是JDK实现的观察者接口,其中就有一个update方法:

//观察者接口public interface Observer {    void update(Observable o, Object arg);}

而被观察者java.util.Observable是采用类被继承的方式设计的:

/*JDK中被观察者类的实现 *其他代码删除了,具体参考JDK源码 * @since   JDK1.0 */public class Observable {    private boolean changed = false;    private Vector obs;//存储观察者的集合    public Observable() {        obs = new Vector();    }    //添加观察者    public synchronized void addObserver(Observer o) {    }    //删除观察者    public synchronized void deleteObserver(Observer o) {        obs.removeElement(o);    }    //通知观察者    public void notifyObservers(Object arg) {    }}

我们设计的基本功能Observable中都有实现,且新增了不少方法。还考虑了线程安全、效率问题等。美中不足的是,你如果想使用这个类,那就得继承它,这势必会影响你的其他设计(单继承)。自己设计一个被观察者接口也很简单,随便你咯。

总结

  • 观察者模式定义了对象间一对多的关系。
  • 观察者和被之间用松耦合的方式连接,彼此都不知道对方是谁,只知道发出、接收数据,像网恋一样,不管对方是周杰伦还是凤姐,也能快乐的聊天恋爱。
  • 可以更进一步设计数据的获取方式,推或者拉。
阅读全文
1 0
原创粉丝点击