程序员子龙(Java面试 + Java学习) 程序员子龙(Java面试 + Java学习)
首页
学习指南
工具
开源项目
技术书籍

程序员子龙

Java 开发从业者
首页
学习指南
工具
开源项目
技术书籍
  • 基础

  • JVM

  • Spring

  • 并发编程

  • Mybatis

  • 网络编程

  • 数据库

  • 缓存

  • 设计模式

    • 单例模式
    • 工厂模式
    • 观察者模式
      • 简单工厂模式
      • 建造者模式
      • 模板设计模式
      • 使用策略+工厂模式彻底干掉代码中的if else
      • 责任链设计模式
      • 中介者模式
    • 分布式

    • 高并发

    • SpringBoot

    • SpringCloudAlibaba

    • Nginx

    • 面试

    • 生产问题

    • 系统设计

    • 消息中间件

    • Java
    • 设计模式
    程序员子龙
    2024-01-29
    目录

    观察者模式

    # 观察者模式

    # 定义

    观察者模式(Observer Pattern)也叫做发布订阅模式(Publish/subscribe),它是一个在项目中经常使用的模式。定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。通过这种方式来达到减少依赖关系,解耦合的作用。

    我们先来解释一下观察者模式的几个角色名称:

    ● Subject被观察者 定义被观察者必须实现的职责,它必须能够动态地增加、取消观察者。它一般是抽象类或者是实现类,仅仅完成作为被观察者必须实现的职责:管理观察者并通知观察者。

    ● Observer观察者 观察者接收到消息后,即进行update(更新方法)操作,对接收到的信息进行处理。

    ● ConcreteSubject具体的被观察者 定义被观察者自己的业务逻辑,同时定义对哪些事件进行通知。

    ● ConcreteObserver具体的观察者 每个观察在接收到消息后的处理反应是不同,各个观察者有自己的处理逻辑。

    一般类图是这样的

    在软件系统中经常会有这样的需求:如果一个对象的状态发生改变,某些与它相关的对象也要随之做出相应的变化。比如说邮件系统,你在收到一封邮件的时候经常桌面上会有通知,告诉你有邮件收到了。 观察者模式特点:那就是一个对象要时刻监听着另一个对象,只要它的状态一发生改变,自己随之要做出相应的行动。

    # 简单代码实现

    1、被观察者

    被观察者的职责非常简单,就是定义谁能够观察,谁不能观察

    /**
     * 被观察者
     * @version 1.0.0
     * @date 2021/12/01 16:39
     */
    public class Subject {
    
        /**
         * 定义一个观察者数组
         */
        private List<Observer> observerList = new ArrayList<>();
    
        /**
         * 增加一个观察者
         * @param o
         */
        public void addObserver(Observer o){
            this.observerList.add(o);
        }
    
        /**
         * 删除一个观察者
         * @param o
         */
        public void delObserver(Observer o){
            this.observerList.remove(o);
        }
    
        /**
         * 通知所有观察者
         */
        public void notifyObservers(){
            for(Observer o :this.observerList){
                o.update();
            }
        }
    
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39

    2、具体被观察者

    /**
     * 具体被观察者
     * @version 1.0.0
     * @date 2021/12/01 17:04
     */
    public class ConcreteSubject extends Subject{
    
        //具体的业务
        public void doSomething(){
            /*
             * do something
             */
            super.notifyObservers();
        }
    
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

    3、观察者

    /**
     * 观察者
     * @version 1.0.0
     * @date 2021/12/01 16:41
     */
    public interface Observer {
    
        //更新方法
        public void update();
    
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11

    4、具体观察者

    /**
     * 具体观察者
     * @version 1.0.0
     * @date 2021/12/01 16:46
     */
    public class ConcreteObserver implements Observer{
    
        /**
         * 实现更新方法
         */
        @Override
        public void update() {
            System.out.println("接收到信息,并进行处理!");
    
        }
    }
    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17

    5、测试类

    public class Client {
    
        public static void main(String[] args) {
            //创建一个被观察者
            ConcreteSubject subject = new ConcreteSubject();
            //定义一个观察者
            Observer obs= new ConcreteObserver();
            //观察者观察被观察者
            subject.addObserver(obs);
            //观察者开始活动了
            subject.doSomething();
        }
    
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14

    # 优点

    1、观察者和被观察者之间是抽象耦合 不管是增加观察者还是被观察者都非常容易扩展,而且在Java中都已经实现的抽象层级的定义,在系统扩展方面更是得心应手。

    2、建立一套触发机制

    根据单一职责原则,每个类的职责是单一的,那么怎么把各个单一的职责串联成真实世界的复杂的逻辑关系呢?观察者模式是一种常用的触发机制,它形成一条触发链,依次对各个观察者的方法进行处理。但同时,这也算是观察者模式一个缺点,由于是链式触发,当观察者比较多的时候,性能问题是比较令人担忧的。

    # 使用场景

    • 关联行为场景。需要注意的是,关联行为是可拆分的,而不是“组合”关系。
    • 事件多级触发场景。当一个对象在不知道对方具体是如何实现时需要通知其它对象。
    • 跨系统的消息交换场景,如消息队列的处理机制。
    • 当一个对象改变需要通知不确定数的对象时

    # 实际应用

    发送消息,消息是被观察者,用户是观察者

    1、被观察者

    public interface Subject {
    
        // 添加订阅关系
        void attach(Observer observer);
        // 移除订阅关系
        void detach(Observer observer);
        // 通知订阅者
        void notifyObservers(String message);
    
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    2、具体被观察者

    public class ConcreteSubject implements Subject{
    
        // 订阅者容器
        private List<Observer> observers = new ArrayList<Observer>();
    
        @Override
        public void attach(Observer observer) {
            // 添加订阅关系
            observers.add(observer);
        }
    
        @Override
        public void detach(Observer observer) {
            // 移除订阅关系
            observers.remove(observer);
        }
    
        @Override
        public void notifyObservers(String message) {
            // 通知订阅者
            for (Observer observer : observers) {
                observer.update(message);
            }
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25

    3、观察者

    public interface Observer {
    
        //更新方法
        public void update(String message);
    
    }
    
    1
    2
    3
    4
    5
    6

    4、具体观察者

    public class ConcreteObserver implements Observer{
    
        @Override
        public void update(String message) {
            // 模拟处理业务逻辑
            System.out.println("用户收到消息:" + message);
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8

    5、测试

    public class Client {
    
        public static void main(String[] args) {
    
            ConcreteSubject subject = new ConcreteSubject();
            // 这里假设是增加新用户
            subject.attach(new ConcreteObserver());
            ConcreteObserver twoObserver = new ConcreteObserver();
            subject.attach(twoObserver);
    
            // 发送朋友圈动态
            subject.notifyObservers("第一条消息");
    
            subject.detach(twoObserver);
            
            subject.notifyObservers("第二个消息");
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

    运行结果

    用户收到消息:第一条消息 用户收到消息:第一条消息 用户收到消息:第二个消息

    可以看到,ConcreteSubject 维护了一个订阅关系,在通过notifyObservers 方法通知订阅者之后,观察者都获取到消息从而处理自己的业务逻辑。如果有新的业务添加进来,我们也只需要创建一个新的订阅者,并且维护到observers 容器中即可,也符合我们的开闭原则。

    上面代码依赖关系

    # 总结

    观察者模式是围绕了解耦的思想来写的,观察者模式作为行为型设计模式,主要也是为了不同的业务行为的代码解耦。

    合理的使用设计模式可以使代码结构更加清晰,同时还能满足不同的小模块符合单一职责,以及开闭原则,提高代码的可扩展性,维护成本低的特点。

    上次更新: 2024/03/11, 15:54:57
    工厂模式
    简单工厂模式

    ← 工厂模式 简单工厂模式→

    最近更新
    01
    一个注解,优雅的实现接口幂等性
    11-17
    02
    MySQL事务(超详细!!!)
    10-14
    03
    阿里二面:Kafka中如何保证消息的顺序性?这周被问到两次了
    10-09
    更多文章>
    Theme by Vdoing | Copyright © 2024-2024

        辽ICP备2023001503号-2

    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式