前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >观察者模式

观察者模式

作者头像
JavaEdge
发布2018-05-16 10:18:06
7200
发布2018-05-16 10:18:06
举报
文章被收录于专栏:JavaEdgeJavaEdge

观察者模式从名字上来看大概就是一种通知与被通知的关系,其实代码思想也与其差不多,其核心思想就是有一个或N个观察者(Observer)和一个(或N个)被观察者(Observable 或 Subject),观察者以订阅方式来观察被观察者,当被观察者接到更新时(程序员控制或代码自动发出)将通知所有观察者来接受更新的内容。这就有点像一群学生(Observer,观察者)和书店老板(Observable 或 Subject,被观察者),当书店每次新进漫画杂志时,就会通知所有学生去购买。下面就看看如何用代码来实现这个事件。

观察者模式是另一种可被Lambda 表达式简化和改进的行为模式。在观察者模式中,被观察者持有一个观察者列表。当被观察者的状态发生改变,会通知观察者。观察者模式被大 量应用于基于MVC 的GUI 工具中,以此让模型状态发生变化时,自动刷新视图模块,达到二者之间的解耦。 观看GUI 模块自动刷新有点枯燥,我们要观察的对象是月球! NASA 和外星人都对登陆到月球上的东西感兴趣,都希望可以记录这些信息。NASA 希望确保阿波罗号上的航天员成功登月;外星人则希望在NASA 注意力分散之时进犯地球。

让我们先来定义观察者的API, 这里我将观察者称作LandingObserver。它只有一个 observeLanding 方法,当有东西登陆到月球上时会调用该方法

代码语言:javascript
复制
用于观察登陆到月球的组织的接口
public interface LandingObserver {
       public void observeLanding(String name);
}

被观察者是月球Moon,它持有一组LandingObserver 实例,有东西着陆时会通知这些观察者,还可以增加新的LandingObserver 实例观测Moon 对象

代码语言:javascript
复制
Moon 类当然不如现实世界中那么完美
public class Moon {
       private final List<LandingObserver> observers = new ArrayList<>();

       public void land(String name) {
                    for (LandingObserver observer : observers) {
                         observer.observeLanding(name);
                   } 
       }

      public void startSpying(LandingObserver observer) {
                    observers.add(observer);
      }
}

我们有两个具体的类实现了LandingObserver 接口,分别代表外星人和NASA检测着陆情况。前面提到过,监测到登陆后它们有不同的反应。 外星人观察到人类登陆月球

代码语言:javascript
复制
public class Aliens implements LandingObserver {
       @Override
       public void observeLanding(String name) {
              if (name.contains("Apollo")) {
                      System.out.println("They're distracted, lets invade earth!");
             }
        }
}

NASA 也能观察到有人登陆月球
public class Nasa implements LandingObserver {
       @Override
       public void observeLanding(String name) {
              if (name.contains("Apollo")) {
                       System.out.println("We made it!");
              }
       }
}

和前面的模式类似,在传统的例子中,用户代码需要有一层模板类,如果使用Lambda 表达式,就不用编写这些类了

代码语言:javascript
复制
使用类的方式构建用户代码
Moon moon = new Moon();
moon.startSpying(new Nasa());
moon.startSpying(new Aliens());
moon.land("An asteroid");
moon.land("Apollo 11");



使用Lambda 表达式构建用户代码
Moon moon = new Moon();

moon.startSpying(name -> {
        if (name.contains("Apollo"))
                System.out.println("We made it!");
});

moon.startSpying(name -> {
           if (name.contains("Apollo"))
                System.out.println("They're distracted, lets invade earth!");
});

moon.land("An asteroid");
moon.land("Apollo 11");

还有一点值得思考,无论使用观察者模式或策略模式,实现时采用Lambda 表达式还是传统的类,取决于策略和观察者代码的复杂度。我这里所举的例子代码很简单,只是一两个 方法调用,很适合展示新的语言特性。然而在有些情况下,观察者本身就是一个很复杂的类,这时将很多代码塞进一个方法中会大大降低代码的可读性。

从某种角度来说,将大量代码塞进一个方法会让可读性变差是决定如何使用Lambda 表达式的黄金法则。之所以不在这里过分强调,是因为这也是编写一般方法时的黄金法则!

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.11.19 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档