• 行为型设计模式之观察者模式


    观察者模式

    观察者模式,又叫发布-订阅模式,它属于行为型模式。它是定义一种一对多的依赖关系,一个主题对象可被多个观察者对象同时监听,使得每当主题对象状态变化时,所有依赖于它的对象都会得到通知并被自动更新。

    观察者模式的核心是将观察者与被观察者解耦,以类似于消息/广播发送的机制联动两者,使被观察者的变动能通知到感兴趣的观察者们,从而做出相应的响应。

    在这里插入图片描述

    应用场景

    1.当一个抽象模型包含两个方面内容,其中一个方面依赖于另一个方面;
    
    2.其他一个或多个对象的变化依赖于另一个对象的变化;
    
    3.实现类以广播机制的功能,无需知道具体收听者,只需分发广播,系统中感兴趣的对象会自动接收该广播;
    
    4.多层级嵌套使用,形成一种链式触发机制,使得事件具备跨域(跨越两种观察者类型)通知。
    

    例如:某商品无货时,只需要订阅到货通知,当产品到货时, 就可以向所有顾客发送消息通知,避免顾客重复、多次访问查询是否有货。

    主要角色

    1.抽象主题(Subject)

    指被观察的对象(Observable)。该角色是一个抽象类或接口,定义了增加、删除、通知观察者对象的方法;

    2.具体主题(ConcreteSubject)

    具体被观察者,当其内状态变化时,会通知已注册的观察者;

    3.抽象观察者(Observer)

    定义了响应通知的更新方法

    4.具体观察者(ConcrereObserver)

    在得到状态更新时,会自动做出响应。

    在这里插入图片描述

    优缺点

    优点:

    1.观察者和被观察者是松耦合(抽象耦合)的,符合依赖倒置原则;
    
    2.分离了表示层(观察者)和数据逻辑层(被观察者),并且建立了一套触发机制,使得数据的变化可以响应到多个表示层上;
    
    3.实现了一对多的通讯机制,支持事件注册机制,支持兴趣分发机制,当被观察者触发事件时,只有感兴趣的观察者可以接收到通知。
    

    缺点:

    1.如果观察者数量过多,则事件通知会耗时较长;
    
    2.事件通知呈线性关系,如果其中一个观察者处理事件卡壳,会影响后续的观察者接收该事件;
    
    3.如果观察者和被观察者之间存在循环依赖,则可能造成两者之间的循环调用,导致系统崩溃。
    

    基本使用

    创建抽象主题

    public interface ISubject<E> {
        void add(IObserver<E> observer);
        
        void notify(E event);
    }
    

    创建具体主题

    public class ConcreteSubject<E> implements ISubject<E> {
        private List<IObserver<E>> observers = new ArrayList<IObserver<E>>();
    
        public void add(IObserver<E> observer) {
            if (observer != null && !observers.contains(observer)) {
                this.observers.add(observer);
            }
        }
    
    
        public void notify(E event) {
            System.out.println("准备通知观察者,通知内容:" + event);
            for (IObserver<E> observer : this.observers) {
                observer.update(event);
            }
        }
    }
    

    创建抽象观察者

    public interface IObserver<E> {
        void update(E event);
    }
    

    创建具体观察者

    public class ConcreteObserver<E> implements IObserver<E> {
        public void update(E event) {
            System.out.println("具体观察者得到通知,通知内容: " + event);
        }
    }
    

    客户端执行

        public static void main(String[] args) {
            // 被观察者
            ISubject<String> observable = new ConcreteSubject<String>();
            // 观察者
            IObserver<String> observer1 = new ConcreteObserver<String>();
            IObserver<String> observer2 = new ConcreteObserver<String>();
            // 新增观察者
            observable.add(observer1);
            observable.add(observer2);
            // 通知观察者
            observable.notify("hello world");
        }
    
    
    准备通知观察者,通知内容:hello world
    具体观察者得到通知,通知内容: hello world
    具体观察者得到通知,通知内容: hello world
    

    JDK中的Observer

    JDK提供的一种观察者的实现方式,被观察者。

    创建具体主题

    @Data
    public class ConcreteSubject extends Observable {
        private String name = "被观察者1号";
    
        private static final ConcreteSubject CONCRETE_SUBJECT = new ConcreteSubject();
    
        public static ConcreteSubject getInstance() {
            return CONCRETE_SUBJECT;
        }
    
        public void pushMsg(String msg) {
            System.out.println(this.name + "发布了一条新消息:" + msg + " ,准备通知观察者");
            setChanged();
            notifyObservers(msg);
        }
    }
    

    创建具体观察者

    public class ConcrereObserver implements Observer {
    
        private String name;
    
        public ConcrereObserver(String name) {
            this.name = name;
        }
    
        public void update(Observable o, Object arg) {
            ConcreteSubject concreteSubject = (ConcreteSubject) o;
            String msg = (String) arg;
            System.out.println(this.name + "收到了新消息:" + msg + ",准备响应: " + concreteSubject.getName());
        }
    }
    

    客户端执行

        public static void main(String[] args) {
            // 创建被观察者
            ConcreteSubject concreteSubject = ConcreteSubject.getInstance();
            // 创建观察者
            ConcrereObserver concrereObserver1 = new ConcrereObserver("观察者1号");
            ConcrereObserver concrereObserver2 = new ConcrereObserver("观察者2号");
    
            // 新增观察者
            concreteSubject.addObserver(concrereObserver1);
            concreteSubject.addObserver(concrereObserver2);
    
            // 通知观察者
            concreteSubject.pushMsg("hello world");
        }
    
    被观察者1号发布了一条新消息:hello world ,准备通知观察者
    观察者2号收到了新消息:hello world,准备响应: 被观察者1号
    观察者1号收到了新消息:hello world,准备响应: 被观察者1

    Guava API实现观察者模式

    添加依赖

    	    <dependency>
                <groupId>com.google.guava</groupId>
                <artifactId>guava</artifactId>
                <version>20.0</version>
            </dependency>
    

    创建监听事件

    public class MyEvent {
    
        @Subscribe
        public void observer(String msg) {
            System.out.println("收到消息:" + msg);
        }
    }
    

    客户端执行

        public static void main(String[] args) {
            EventBus eventBus = new EventBus();
    
            MyEvent myEvent = new MyEvent();
            eventBus.register(myEvent);
            eventBus.post("hello world");
        }
    
    收到消息:hello world
    
  • 相关阅读:
    C++ Lambda表达式
    Windows11 家庭版开启远程桌面解决方案之RDP Wrapper Library,小白全面攻略
    【AI工具之Prezo如何自动生成PPT操作步骤】
    [NOIP2002 普及组] 产生数
    ORB-SLAM2 ---- Initializer::ReconstructF函数
    【leetcode】【剑指offer Ⅱ】048. 序列化与反序列化二叉树
    微前端是模块化后的最终选择
    「项目管理工具」进度猫如何实现可视化?
    给老婆写的,每日自动推送暖心消息
    是谁在Go标准库的源码中植入了色情网站?
  • 原文地址:https://blog.csdn.net/qq_38628046/article/details/126237004