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

设计模式是进阶高级开发的必经之路。掌握设计模式,才能提升编码能力,设计出可复用、可扩展、可维护的软件系统。了解设计模式,才能更好理解开源类库的实现原理,解决问题。
观察者模式(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----说:我正在发数据给--Aboy
Aboy------说:我接收到--Taobao--发来数据:  你买的娃娃已经发货啦___
Taobao----说:我正在发数据给--Bboy
Bboy------说:我接收到--Taobao--发来数据:  你买的娃娃已经发货啦___
WeChatPublicSignal说:我正在发数据给Aboy
Aboy------说:我接收到--WeChatPublicSignal--发来数据:  咪蒙说:外国人那么大,我想去看看
WeChatPublicSignal说:我正在发数据给Cgirl
Cgirl-----说:我接收到--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
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值