设计模式笔记(六)——观察者模式

1. 是什么——定义

定义对象间的一种一对多的依赖关系,让多个观察者同时监听某一个主题现象,当一个对象的状态发生改变时,会通知所有观察者对象,所有依赖于它的对象都得到通知并被自动更新。

2. 为什么——特点

一个对象状态改变的同时,需要同时改变其他对象。

3. 什么时候用——适用性

l  一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。

l  一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。

l  一个对象的改变将导致其他一个或多个对象也发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。

l  一个对象必须通知其他对象,而并不知道这些对象是谁。

l  需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。

4. UML图

203806_9WnT_3041734.png
 

5. 怎么用——使用方法

需求:

气象局发布天气预报,学生和上班族根据天气做出相应反应。

5.1  气象局

设计WeatherStation:

内部维护一个{“晴天”, “下雨”, “雾霾”, “冰雹”, “狂风”, “暴雪”}

气象局要根据观测进行天气更新

updateWeather();

气象局要不断工作,不断观测天气:

死循环中每隔1-2秒执行一次

updateWeather() {
    while(true){
        //更新天气
    }
}

 

5.2  学生

学生要设计看天气预报的方法

notifyWeather();

注意这里可以给气象局的weather只设置get方法,这样别人只能看

让学生每次都去看气象局的天气,也就是在notify方法中传入天气

这里使用简单if,else-if,else结构:

l  晴天——开心上学

l  下雨——打着雨伞上学

l  雾霾——开心的吸着毒上学

l  冰雹——学校门口砸了个大坑,不去上学

l  狂风——学校被吹走了,不去上学

l  暴雪——学校门口被雪埋了,不去上学

public void notifyWeather(String weather) {
    if ("晴天".equals(weather)) {
        System.out.println(name + "开开心心的上学!");
    }else if ("下雨".equals(weather)) {
        System.out.println(name + "打伞上学!");
    }else if ("雾霾".equals(weather)) {
        System.out.println(name + "开心的吸着毒上学!");
    }else if ("冰雹".equals(weather)) {
        System.out.println("学校门口被砸了个坑,不去了!");
    }else if ("下雪".equals(weather)) {
        System.out.println("学校门口被雪埋了,不去上学!");
    }else if ("狂风".equals(weather)) {
        System.out.println("学校被吹走了,没学上了!");
    }
}

之后,在Client中编写:

while(true){
    student.notifyWeather(station.getWeather());
}

发现这种方法实在太差,这样学生啥也别干了,光盯着天气预报算了。

而且,如果只是这样,会在客户端留下一个非常严重的问题:

因为气象局一直在观测天气,所以work()方法后面的代码永远无法执行

5.3  解决代码无法执行的bug

new Thread(new Runnable() { 
   @Override
   public void run() {
      while(true){
         updateWeather();
         int s = random.nextInt(1000)+1000;
         try {
            Thread.sleep(s);
         } catch (InterruptedException e) {
            e.printStackTrace();
         }
      }          
   }
}).start();

运行之后发现会出现观察时间与气象局更新时间不匹配的bug。

问题:现在是人主动去关注天气,能不能让气象局播天气预报?

5.4  气象局维护学生

新建一个方法:

addStudent();

每次更新天气时,迭代学生列表,通知学生

public void updateWeather() throws Exception {
    while (true) {
        weather = weathers[random.nextInt(weathers.length)];
        System.out.println("当前的天气是:" + weather);
        for (Student student : students) {
            student.notifyWeather(weather);
        }
        Thread.sleep(random.nextInt(1000) + 1000);
    }
}

到此为止,已经构成了观察者模式

5.5  新增上班族

l  晴天——开心上班

l  下雨——打着雨伞上班

l  雾霾——带着消毒面具上班

l  冰雹——带着三级头盔上班

l  狂风——拖着大石头上班

l  暴雪——披着被子上班

public void notifyWeather(String weather) {
    if ("晴天".equals(weather)) {
        System.out.println(name + "开开心心的上班!");
    }else if ("下雨".equals(weather)) {
        System.out.println(name + "打伞上班!");
    }else if ("雾霾".equals(weather)) {
        System.out.println(name + "戴着防毒面具上班!");
    }else if ("冰雹".equals(weather)) {
        System.out.println(name + "戴着三级头去上班");
    }else if ("下雪".equals(weather)) {
        System.out.println(name + "披着被子去上班");
    }else if ("狂风".equals(weather)) {
        System.out.println(name + "拖着大石头上班!");
    }
}

5.6  气象局维护上班族

试着在Client中创建Employee的对象。。。

发现在Client中不能addEmployee!

 

观察上班族和学生,他们都有一个共同的特点:

看天气预报!根据天气不同,作出不同的反应!

这属于行为——可以抽出一个接口(面向接口编程而不是实现类)

5.7  抽取被通知者

public interface Observable {
    public void notifyWeather(String weather);
}

之后,在气象局中使用多态即可。

5.8  新增天气预报软件,抽取天气通知类型(观察者)

无需多言,与上面的思路完全一致。

 

6. 实际应用

其实,Java的GUI实现的组件事件监听,本质就是观察者模式。

----当某个按钮被点击时,要通知另一些组件作出反应(如点击全选,所有复选框被选中)

但发现:GUI的事件监听机制是使用匿名内部类!

button.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        System.out.println("我被点击了。。。");
    }
});

这种设计思路是:只要被通知的对象符合一定的特征即可!

这不就是匿名内部类的使用思路吗???(突然滑稽)

 

7. Java中的观察者模式支持

翻开java.util包,可以发现一个类和一个接口:

Observer类,Observable接口

204422_LAqm_3041734.png

204456_V6TQ_3041734.png

实现Observable接口的,都是被通知对象。

Observer本身就可以通知,当然可以继承Observer类,扩展功能。。。

 

注--- 使用jdk自带的观察者模式的缺点:

  • Observable是一个类,而不是一个接口,导致Observable类的扩展性不高,不如自己实现的观察者模式灵活
  • Observable将某些方法保护了起来(setChanged()和clearChanged()为protected),这意味着除非继承自Observable,否则将有关键的方法不能调用。导致无法通过组合的方式使其它类获得Observable类的功能

转载于:https://my.oschina.net/LinkedBear/blog/1791975

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值