1. 1 不可撤销
  2. 2 小年兽 程嘉敏
  3. 3 手放开 李圣杰
  4. 4 迷人的危险3(翻自 dance flow) FAFA
  5. 5 山楂树之恋 程佳佳
  6. 6 summertime cinnamons / evening cinema
  7. 7 不谓侠(Cover 萧忆情Alex) CRITTY
  8. 8 神武醉相思(翻自 优我女团) 双笙
  9. 9 空山新雨后 音阙诗听 / 锦零
  10. 10 Wonderful U (Demo Version) AGA
  11. 11 广寒宫 丸子呦
  12. 12 陪我看日出 回音哥
  13. 13 春夏秋冬的你 王宇良
  14. 14 世界が终わるまでは… WANDS
  15. 15 多想在平庸的生活拥抱你 隔壁老樊
  16. 16 千禧 徐秉龙
  17. 17 我的一个道姑朋友 双笙
  18. 18 大鱼  (Cover 周深) 双笙
  19. 19 霜雪千年(Cover 洛天依 / 乐正绫) 双笙 / 封茗囧菌
  20. 20 云烟成雨(翻自 房东的猫) 周玥
  21. 21 情深深雨濛濛 杨胖雨
  22. 22 Five Hundred Miles Justin Timberlake / Carey Mulligan / Stark Sands
  23. 23 斑马斑马 房东的猫
  24. 24 See You Again Wiz Khalifa / Charlie Puth
  25. 25 Faded Alan Walker / Iselin Solheim
  26. 26 Natural J.Fla
  27. 27 New Soul Vox Angeli
  28. 28 ハレハレヤ(朗朗晴天)(翻自 v flower) 猫瑾
  29. 29 像鱼 王贰浪
  30. 30 Bye Bye Bye Lovestoned
  31. 31 Blame You 眠 / Lopu$
  32. 32 Believer J.Fla
  33. 33 书信 戴羽彤
  34. 34 柴 鱼 の c a l l i n g【已售】 幸子小姐拜托了
  35. 35 夜空中最亮的星(翻自 逃跑计划) 戴羽彤
  36. 36 慢慢喜欢你 LIve版(翻自 莫文蔚) 戴羽彤
  37. 37 病变(翻自 cubi) 戴羽彤
  38. 38 那女孩对我说 (完整版) Uu
  39. 39 绿色 陈雪凝
  40. 40 月牙湾 LIve版(翻自 F.I.R.) 戴羽彤
夜空中最亮的星(翻自 逃跑计划) - 戴羽彤
00:00 / 04:10

夜空中最亮的星 能否听清

那仰望的人 心底的孤独和叹息

夜空中最亮的星 能否记起

那曾与我同行 消失在风里的身影

我祈祷拥有一颗透明的心灵

和会流泪的眼睛

给我再去相信的勇气

越过谎言去拥抱你

每当我找不到存在的意义

每当我迷失在黑夜里

噢喔喔 夜空中最亮的星

请指引我靠近你

夜空中最亮的星 是否知道

那曾与我同行的身影 如今在哪里

夜空中最亮的星 是否在意

是等太阳先升起 还是意外先来临

我宁愿所有痛苦都留在心底

也不愿忘记你的眼睛

哦 给我再去相信的勇气

哦 越过谎言去拥抱你

每当我找不到存在的意义

每当我迷失在黑夜里

噢喔喔 夜空中最亮的星

请照亮我向前行 哒~

我祈祷拥有一颗透明的心灵

和会流泪的眼睛 哦

给我再去相信的勇气

哦 越过谎言去拥抱你

每当我找不到存在的意义

每当我迷失在黑夜里

噢喔喔 夜空中最亮的星

请照亮我向前行

设计模式详解——观察者模式

前言

今天我们来看下一个可以有效实现松耦合的设计模式——观察者模式,这个设计模式我之前也仅仅停留在听说过的层面,关于它的具体实现更是一知半解,所以今天我们就来简单剖析下这个设计模式。

设计模式

观察者模式

观察者模式定义了对象之间的一对多依赖,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

要点
  • 观察者模式定义了对象之间一对多的关系
  • 主题(可观察者)用一个共同的接口来更新观察者
  • 观察者和可观察者之间用松耦合方式结合,可观察者不知道观察者的细节,只知道观察者实现了观察者接口
  • 使用次模式时,你可以从被观察者处推或拉数据(推的方式被认为是更正确的)
  • 有多个观察者时,不可以依赖特定的通知次序
  • java中有多种观察者模式的实现,包括了通用的java.util.Observable,不过需要注意Observable实现上所带来的问题,有必要的话,可以实现自己的Observable
  • Swing大量使用观察者模式,许多GUI框架也是如此
  • 观察者模式还广泛被应用在许多地方,比如:JavaBeansRMI
示例

下面我们以一个具体实例,来展示下观察者模式的具体实现。这里我们就直接以《Head First设计模式》中的气象站为例,其中天气信息就表示被观察者,天气布告板就表示订阅者和观察者,当天气发生变化(被观察者)时,会通过notifyObserver通知所有观察者,并调用他们的控制方法处理数据。下面我们就来看下具体实现过程

被观察者接口接口

这里有三个方法,第一个是注册观察者,第二个是移除观察者,第三个是通知观察者

public interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObserver();
}
观察者接口

观察者接口就一个方法,主要用于更新从被观察者中获取到的数据,该方法会在被注册者的notifyObserver方法中被调用

public interface Observer {
    void update(float temp, float humidity, float pressure);
}
控制层接口

这个接口主要是用于处理被观察者更新的数据,核心方法就一个。

public interface DisplayElement {
    void display();
}
被观察者实现

这里是被观察者的具体实现,被观察者也可以叫数据源,当数据发生变化时,由它负责告知观察者。

public class WeatherData implements Subject {
    private List<Observer> observerList;
    private float temp;
    private float humidity;
    private float pressure;

    public WeatherData(List<Observer> observerList) {
        this.observerList = observerList;
    }

    @Override
    public void registerObserver(Observer observer) {
        observerList.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observerList.remove(observer);
    }

    @Override
    public void notifyObserver() {
        observerList.forEach(observer -> observer.update(temp, humidity, pressure));
    }

    public void measurementChanged() {
        notifyObserver();
    }

    public void setMeasurements(float temp, float humidity, float pressure) {
        this.temp = temp;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementChanged();
    }
}
观察者实现

观察者我们实现了两个,主要是便于后面测试。这两个实现处理名字不一样,其他代码都是一样的。

public class RemoteDisplay implements Observer, DisplayElement {

    private Subject subject;
    private float temp;
    private float humidity;
    private float pressure;

    public RemoteDisplay(Subject subject) {
        this.subject = subject;
        subject.registerObserver(this);
    }

    @Override
    public void display() {
        System.out.println(String.format("======= \nname:%s \ntemp:%S \nhumidity:%s \npressure:%s", "remote", temp, humidity, pressure));
    }

    @Override
    public void update(float temp, float humidity, float pressure) {
        this.temp = temp;
        this.humidity = humidity;
        this.pressure = pressure;
        display();
    }
}

public class CurrentWeatherDataDisplay implements Observer, DisplayElement {

    private Subject subject;
    private float temp;
    private float humidity;
    private float pressure;

    public CurrentWeatherDataDisplay(Subject subject) {
        this.subject = subject;
        subject.registerObserver(this);
    }

    @Override
    public void display() {
        System.out.println(String.format("======= \nname:%s \ntemp:%S \nhumidity:%s \npressure:%s", "urrentWeatherData", temp, humidity, pressure));
    }

    @Override
    public void update(float temp, float humidity, float pressure) {
        this.temp = temp;
        this.humidity = humidity;
        this.pressure = pressure;
        display();
    }
}
测试代码

从上面观察者的实现类中,我们可以看出来,在实例化观察者的时候,其实已经完成了注册操作,所以这里我们不再需要手动注册观察者,后面再被观察者(数据)发生变化时,观察者会实时被通知。

@Test
    public void testWeatherDisplay() {
        WeatherData data = new WeatherData(new ArrayList<>());
        new CurrentWeatherDataDisplay(data);
        new RemoteDisplay(data);
        data.setMeasurements(12, 88, 981);
        System.out.println("----------------分割线------------------");
        data.setMeasurements(28, 68, 871);
        System.out.println("----------------分割线------------------");
        data.setMeasurements(38, 48, 681);
    }
运作结果

总结

从实例的运行结果来看,观察者模式特别适用于那些一对多的应用场景,比如数据推送同步,当你的平台数量发生变化时,数据发送方只需要将相关平台注册或删除,即可完成观察者的变更,可以实现代码之间的松耦合,提升代码的扩展性。

与这个设计模式类似的设计模式是订阅者模式,这两种设计模式,在我之前的认知中,我觉得他们应该是一样的,但是今天查阅了相关资料之后,发现它们并不完全一样,这里我们先大概对订阅者模式有一个基本的认知,后面等我们分享完订阅者模式之后,我们再来比较这两个的区别。

posted @ 2021-10-15 22:05  云中志  阅读(15)  评论(0编辑  收藏  举报