手记

观察者模式

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

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

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

用于观察登陆到月球的组织的接口public interface LandingObserver {       public void observeLanding(String name);
}

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

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检测着陆情况。前面提到过,监测到登陆后它们有不同的反应。
外星人观察到人类登陆月球

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 表达式,就不用编写这些类了

使用类的方式构建用户代码
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 表达式的黄金法则。之所以不在这里过分强调,是因为这也是编写一般方法时的黄金法则!



作者:芥末无疆sss
链接:https://www.jianshu.com/p/88dd90afa5d7
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。


0人推荐
随时随地看视频
慕课网APP