Skip to content

观察者模式:原来观察者模式是JDK与生俱来的

lvgo edited this page Nov 28, 2020 · 1 revision

observer-title.png

观察者模式

多个对象间存在一对多关系,当一个对象发生改变时,把这种改变通知给其他多个对象,从而影响其他对象的行为。

提到观察者,就一定有“被观察者”。

被观察者发生改变时,通知给每个观察者,这就是观察者模式。放到生活中的例子就是

  • 天气预报的短信通知,在很早以前,我们的天气预报服务可以通过短信的信息订阅。在这个业务场景中,天气预报就是被观察者,每个付费的用户就是观察者,当有最新的天气预报的消息时,会以短信的形式通知给曾经付过费订阅的用户。如果不订阅是不会收到的。
  • 你现在在使用的通讯软件中的'群聊'功能,这个相对较为复杂一点,可以抽象的理解一下,用一个人去理解,群里的每个人都是被观察者,每个人都是观察者。当一个人发出消息的时候,所有在群里的人都会收到消息也包括自己。反之,不在群里的人则收不到。
  • 还记得小区单元门口一个一个小盒子吗?有的小盒子里是有当天的报纸的。甚至里面的报纸内容可能是不相同的,这里就涉及到了多个被观察者和观察之间的关系,这个小盒子能收到自己订阅的报社报纸,当然你可以同时订阅多个,这样你就可以收到多个报社送过来的报纸了。

对于上面的例子,天气预报需要用户自己付费订阅、群聊需要先进群、在家看报需要联系报社订阅报纸。这里就能看出来。这种关系是一个一对多的关系。被观察者是同一个,而观察者却可以是很多个不同的对象。还有就是观察者需要自己主动的去找被观察者“提前”说明好,“一旦有消息,请通知我一声”。所有这里可以抽象出来几个角色和动作。

  1. 被观察者(1个)
  2. 观察者(n个)
  3. 被观察者负责管理观察者对象
  4. 观察者自己负责被观察者给予的通知内容

观察者模式类图 📌

observer-UML.png

  1. 被观察者(Observable)
  2. 观察者(Observer)
  3. 被观察者负责管理观察者对象(Observable.obs)
  4. 观察者自己负责被观察者给予的通知内容(Observer.update)

如果对 JDK 熟悉的同学可能早已看穿,这个类图画的其实就是 JDK 提供的观察者框架,我们可以用它轻松的实现一个订阅通知功能。而这一功能在 JDK 1.0 的版本就已经存在了。

代码 📃

JDK 源码,篇幅原因只保留了核心代码

package java.util;
// 观察者
public interface Observer {
    void update(Observable var1, Object var2);
}

JDK 源码,篇幅原因只保留了核心代码

package java.util;
// 被观察者
public class Observable {
	// 管理观察者对象
    private final Vector<Observer> obs = new Vector();

    public synchronized void addObserver(Observer var1) {
        if (!this.obs.contains(var1)) {
            this.obs.addElement(var1);
        }
    }
    // 通知给订阅的观察者
 	public void notifyObservers(Object var1) {
        Object[] var2 = this.obs.toArray();
        for(int var3 = var2.length - 1; var3 >= 0; --var3) {
            ((Observer)var2[var3]).update(this, var1);
        }

    }
}

自己实现部分

public class Producer extends Observable {

    @Override
    public  synchronized void setChanged() {
        super.setChanged();
    }
}
public class Consumer1 implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("我是 consumer1 我收到了" + o + "的通知,通知内容:" + arg);
    }
}
public class Consumer2 implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("我是 consumer2 我收到了" + o + "的通知,通知内容:" + arg);
    }
}
public class Consumer3 implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("我是 consumer3 我收到了" + o + "的通知,通知内容:" + arg);
    }
}

测试,定义了 2 个被观察者(生产者),3 个观察者(消费者)来分别使用12生产者来发布消息。

@Test
void jdkOb() {
    Producer producer1 = new Producer();
    producer1.setChanged();
    Producer producer2 = new Producer();
    producer2.setChanged();
    Consumer1 consumer1 = new Consumer1();
    Consumer2 consumer2 = new Consumer2();
    Consumer3 consumer3 = new Consumer3();

    producer1.addObserver(consumer1);
    producer1.addObserver(consumer2);
    producer1.addObserver(consumer3);
    producer2.addObserver(consumer1);
    producer2.addObserver(consumer2);
    producer2.addObserver(consumer3);

    producer1.notifyObservers("我是生产者1,我现在给你们通知一条消息,收到赶紧去消费掉");
    producer2.notifyObservers("我是生产者2,我现在给你们通知一条消息,收到赶紧去消费掉");
}

测试结果

我是 consumer3 我收到了Producer@57cd70的通知,通知内容:我是生产者1,我现在给你们通知一条消息,收到赶紧去消费掉
我是 consumer2 我收到了Producer@57cd70的通知,通知内容:我是生产者1,我现在给你们通知一条消息,收到赶紧去消费掉
我是 consumer1 我收到了Producer@57cd70的通知,通知内容:我是生产者1,我现在给你们通知一条消息,收到赶紧去消费掉

我是 consumer3 我收到了Producer@1a7504c的通知,通知内容:我是生产者2,我现在给你们通知一条消息,收到赶紧去消费掉
我是 consumer2 我收到了Producer@1a7504c的通知,通知内容:我是生产者2,我现在给你们通知一条消息,收到赶紧去消费掉
我是 consumer1 我收到了Producer@1a7504c的通知,通知内容:我是生产者2,我现在给你们通知一条消息,收到赶紧去消费掉

总结 📚

使用观察者模式需要注意的几个点

  1. 观察者数量,如果一个被观察者被很多观察者观察(订阅)时,在通知时的时间将会变得漫长;
  2. 不能出现被观察者和观察者之间存在循环观察情况,否则系统会直接崩溃;

观察者模式的代码虽然很简单,但是它所创造的价值却远不止这些。相信你同我一样,通过观察者模式联想到了消息通知、binlog订阅、注册中心等技术组件。其核心内容也只是在此简单的不能再简单的思想上去做更多更复杂的功能迭代。

万变不离其宗。在复杂的系统,在复杂的功能,都能找到其根本所在。知识,亦是如此。

当然,你也可以尝试在现有的代码中进行一些修改,比如通知的情况改为有新的观察者加入时?通知的数据变得更丰富一些?异步通知?等等等等。

如果你有更好的点子可以关注并分享给我们(欢迎加群)!

目录

首页_HOME

1. 单例模式: 资源!要合理的分配使用!

2. 原型模式:啥?盗图、盗文章的人居然用的是一种设计模式!原型模式?

3. 工厂模式:像工厂一样创建对象,让业务代码更专注!

4. 抽象工厂模式:抽象工厂模式和工厂模式有区别吗?

5. 建造者模式:学个设计模式还和人生扯上关系了?

6. 代理模式:有什么问题跟我律师说吧!

7. 装饰者模式:玩了把坦克大战居然彻底搞懂了装饰者模式!

8. 桥接模式:这个不常用的设计模式居然被我学的最透,草率了!

9. 适配器模式:今天轻松点,就说说什么是“榫”,什么是“卯”,什么是“榫卯”!

10. 外观模式:书生的家书是谁送的?书童到底是个什么角色?

11. 享元模式:如果让你开发英雄联盟的兵线,你会怎么设计?

12. 组合模式:使用组合模式做一个简单的推荐功能

13. 策略模式:学习JDK的比较器架构是如何设计的

14. 模板方法模式:你知道AQS它是干什么的吧,那这个框架是怎么设计的呢?

15. 观察者模式:原来观察者模式是JDK与生俱来的

16. 责任链模式:“张三为了纪念王二请假的悲催经历想出来的一种设计模式”

17. 备忘录模式:这款游戏你玩过吗?是不是经常”重来“?

18. 迭代器模式:你真的“会”遍历list吗?

19. 命令模式:如果把请求变成一个对象,在一些场景更好用!

20. 状态模式:从工作状态,再到订单状态一点点深入学习状态模式

21. 中介者(Mediator)模式:定义一个中介对象来简化原有对象之间的交互关系,降低系统中对象间的耦合度,使原有对象之间不必相互了解。

22. 访问者模式:是“凡尔赛”让我“认清”了访问者模式!

23. 解释器(Interpreter)模式:提供如何定义语言的文法,以及对语言句子的解释方法,即解释器。


个人博客 Star Dust

Clone this wiki locally