Java设计模式--观察者模式

观察者模式【Observer Pattern 】

观察者模式以秦国时期李斯监视韩非子为例。

先看下类图:

这里写图片描述

被观察者:

public interface IHanFeiZi {
    //韩非子也是人,也要吃早饭的
    public void haveBreakfast();
    //韩非之也是人,是人就要娱乐活动
    public void haveFun();
}

被观察者的实现类:

public class HanFeiZi implements IHanFeiZi{
    //韩非子是否在吃饭,作为监控的判断标准
    private boolean isHaveBreakfast = false;
    //韩非子是否在娱乐
    private boolean isHaveFun = false;
    //韩非子要吃饭了
    public void haveBreakfast(){
    System.out.println("韩非子:开始吃饭了...");
    this.isHaveBreakfast =true;
    }
    //韩非子开始娱乐了,古代人没啥娱乐,你能想到的就那么多
    public void haveFun(){
    System.out.println("韩非子:开始娱乐了...");
    this.isHaveFun = true;
    }
    //以下是bean的基本方法,getter/setter,不多说
    public boolean isHaveBreakfast() {
    return isHaveBreakfast;
    }
    public void setHaveBreakfast(boolean isHaveBreakfast) {
    this.isHaveBreakfast = isHaveBreakfast;
    }
    public boolean isHaveFun() {
    return isHaveFun;
    }
    public void setHaveFun(boolean isHaveFun) {
    this.isHaveFun = isHaveFun;
    }
}

观察者的接口:

public interface ILiSi {
    //一发现别人有动静,自己也要行动起来
    public void update(String context);
}

观察者的实现类:

public class LiSi implements ILiSi{
    //首先李斯是个观察者,一旦韩非子有活动,他就知道,他就要向老板汇报
    public void update(String str){
    System.out.println("李斯:观察到韩非子活动,开始向老板汇报了...");
    this.reportToQiShiHuang(str);
    System.out.println("李斯:汇报完毕,秦老板赏给他两个萝卜吃吃...\n");
    }
    //汇报给秦始皇
    private void reportToQiShiHuang(String reportContext){
    System.out.println("李斯:报告,秦老板!韩非子有活动了--->"+reportContext);
    }
}

全部搞好上面了,就要来个监测程序了。

class Watch extends Thread{
    private HanFeiZi hanFeiZi;
    private LiSi liSi;
    private String type;
    //通过构造函数传递参数,我要监控的是谁,谁来监控,要监控什么
    public Watch(HanFeiZi _hanFeiZi,LiSi _liSi,String _type){
    this.hanFeiZi =_hanFeiZi;
    this.liSi = _liSi;
    this.type = _type;
    }
    @Override
    public void run(){
    while(true){
    if(this.type.equals("breakfast")){ //监控是否在吃早餐
    //如果发现韩非子在吃饭,就通知李斯
    if(this.hanFeiZi.isHaveBreakfast()){
    this.liSi.update("韩非子在吃饭");
    //重置状态,继续监控
    this.hanFeiZi.setHaveBreakfast(false);
    }
    }else{//监控是否在娱乐
    if(this.hanFeiZi.isHaveFun()){
    this.liSi.update("韩非子在娱乐");
    this.hanFeiZi.setHaveFun(false);
    }
    } 
    }
    }
}

这样子是可以完成对韩非子的监测,但仔细想想,就不行了,这样子while(true)开启死循环来进行监测,服务器肯定是受不了的,而且监测的对象只有一个,你以为你是秦始皇。。。还是大出血的修改一下好:韩非子是大人物,肯定会有很多间谍监视的,于是观察者应该提炼出来,观察者要观察的也不只是人家的吃法娱乐吧,故也提炼出来:

这里写图片描述

观察者:

public interface Observable {
    //增加一个观察者
    public void addObserver(Observer observer);
    //删除一个观察者,——我不想让你看了
    public void deleteObserver(Observer observer);
    //既然要观察,我发生改变了他也应该用所动作——通知观察者
    public void notifyObservers(String context);
}

被观察者实现上面的接口:

public class HanFeiZi implements Observable{
    //定义个变长数组,存放所有的观察者
    private ArrayList<Observer> observerList = new ArrayList<Observer>();
    //增加观察者
    public void addObserver(Observer observer){
    this.observerList.add(observer);
    }
    //删除观察者
    public void deleteObserver(Observer observer){
        this.observerList.remove(observer);
    }
    //通知所有的观察者
    public void notifyObservers(String context){
        for(Observer observer:observerList){
        observer.update(context);
        }
    }
    //韩非子要吃饭了
    public void haveBreakfast(){
        System.out.println("韩非子:开始吃饭了...");
        //通知所有的观察者
        this.notifyObservers("韩非子在吃饭");
    }
    //韩非子开始娱乐了,古代人没啥娱乐,你能想到的就那么多
    public void haveFun(){
        System.out.println("韩非子:开始娱乐了...");
        this.notifyObservers("韩非子在娱乐");
    }
}

再看观察者:

public interface Observer {
    //一发现别人有动静,自己也要行动起来
    public void update(String context);
}

然后观察者来实现这个接口即可,有多少个观察者都行。

在主类中:

    //三个观察者产生出来
    Observer liSi = new LiSi();
    Observer wangSi = new WangSi();
    Observer liuSi = new LiuSi();
    //定义出韩非子
    HanFeiZi hanFeiZi = new HanFeiZi();
    //我们后人根据历史,描述这个场景,有三个人在观察韩非子
    hanFeiZi.addObserver(liSi);
    hanFeiZi.addObserver(wangSi);
    hanFeiZi.addObserver(liuSi);

    //然后这里我们看看韩非子在干什么
    hanFeiZi.haveBreakfast();

这样就完成了监视的过程。当然JDK 中提供了:
java.util.Observable 实现类和 java.util.Observer 接口,于是乎上面写的那个例子中的
Observable 接口可以改换成 java.util.Observale 实现类了。

下面看一下通用类图:

这里写图片描述

总结:

使用观察者模式要考虑的问题:
(1)广播链的问题。如果你做过数据库的触发器,你就应该知道有一个触发器链的问题,比如表 A 上写了一个触发器,内容是一个字段更新后更新表 B 的一条数据,而表 B 上也有个触发器,要更新表 C,表 C 也有触发器…,完蛋了,这个数据库基本上就毁掉了!我们的观察者模式也是一样的问题,一个观察者可以有双重身份,即使观察者,也是被观察者,这没什么问题呀,但是链一旦建立,这个逻辑就比较复杂,可维护性非常差,根据经验建议,在一个观察者模式中最多出现一个对象既是观察者也是被观察者,也就是说消息最多转发一次(传递两次) ,这还是比较好控制的;

(2)异步处理问题。被观察者发生动作了,观察者要做出回应,如果观察者比较多,而且处理时间比较长怎么办?那就用异步。

举一个应用场景:

比如你到 ATM 机器上取钱,多次输错密码,卡就会被 ATM吞掉,吞卡动作发生的时候,会触发哪些事件呢?第一摄像头连续快拍,第二,通知监控系统,吞卡发生;
第三,初始化 ATM 机屏幕,返回最初状态,你不能因为就吞了一张卡,整个 ATM 都不能用了吧,一般前两
个动作都是通过观察者模式来完成的。

发布了46 篇原创文章 · 获赞 3 · 访问量 2万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章