观察者模式 订阅
观察者模式(有时又被称为模型(Model)-视图(View)模式、源-收听者(Listener)模式或从属者模式)是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。 展开全文
观察者模式(有时又被称为模型(Model)-视图(View)模式、源-收听者(Listener)模式或从属者模式)是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。
信息
模    式
软件设计模式
外文名
Observer Mode
又称为
发布-订阅模式
中文名
观察者模式
系    统
通常被用来实现事件处理系统
观察者模式基本介绍
观察者模式是一种对象行为模式。它定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。在观察者模式中,主题是通知的发布者,它发出通知时并不需要知道谁是它的观察者,可以有任意数目的观察者订阅并接收通知。观察者模式不仅被广泛应用于软件界面元素之间的交互,在业务对象之间的交互、权限管理等方面也有广泛的应用。 [1]  观察者模式(Observer)完美的将观察者和被观察的对象分离开。举个例子,用户界面可以作为一个观察者,业务数据是被观察者,用户界面观察业务数据的变化,发现数据变化后,就显示在界面上。面向对象设计的一个原则是:系统中的每个类将重点放在某一个功能上,而不是其他方面。一个对象只做一件事情,并且将他做好。观察者模式在模块之间划定了清晰的界限,提高了应用程序的可维护性和重用性。观察者设计模式定义了对象间的一种一对多的组合关系,以便一个对象的状态发生变化时,所有依赖于它的对象都得到通知并自动刷新。
收起全文
精华内容
下载资源
问答
  • 观察者模式
    千次阅读
    2021-09-21 16:57:24

    前言:在现实世界中,许多对象并不是独立存在的,其中一个对象的行为发生改变可能会导致一个或者多个其他对象的行为也发生改变。例如,某种商品的物价上涨时会导致部分商家高兴,而消费者伤心;还有,当我们开车到交叉路口时,遇到红灯会停,遇到绿灯会行。在软件世界也是这样,例如,Excel 中的数据与折线图、饼状图、柱状图之间的关系;MVC 模式中的模型与视图的关系;事件模型中的事件源与事件处理者。所有这些,如果用观察者模式来实现就非常方便。


    一、观察者模式简介

    1.1、观察者模式概述

    观察者模式(Observer),又叫发布-订阅模式(Publish/Subscribe),定义对象间一种一对多的依赖关系(注册),使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新(通知)。说白了就是个注册,通知的过程。

    UML结构图如下:

    观察者模式的结构图

    实现观察者模式时要注意具体目标对象和具体观察者对象之间不能直接调用,否则将使两者之间紧密耦合起来,这违反了面向对象的设计原则。

    观察者模式的主要角色如下:

    • 抽象主题(Subject)角色:也叫抽象目标类,它提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者的抽象方法。

    • 具体主题(Concrete Subject)角色:也叫具体目标类,它实现抽象目标中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象。继承Subject类,在这里实现具体业务,在具体项目中,该类会有很多变种。

    • 抽象观察者(Observer)角色:它是一个抽象类或接口,它包含了一个更新自己的抽象方法,当接到具体主题的更改通知时被调用。

    • 具体观察者(Concrete Observer)角色:实现抽象观察者中定义的抽象方法,以便在得到目标的更改通知时更新自身的状态。

    1.2、观察者模式的优缺点

    观察者模式是一种对象行为型模式,其主要优点如下:

    1. 降低了目标与观察者之间的耦合关系,两者之间是抽象耦合关系。符合依赖倒置原则。

    2. 目标与观察者之间建立了一套触发机制。

    它的主要缺点如下:

    1. 目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。

    2. 当观察者对象很多时,通知的发布会花费很多时间,影响程序的效率。

    1.3、观察者模式注意事项

    1、JAVA 中已经有了对观察者模式的支持类。

    2、避免循环引用。

    3、如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式。

    1.4、异步处理线程安全问题

    被观察者发生动作了,观察者要做出回应,如果观察者比较多,而且处理时间比较长怎么办?那就用异步呗,异步处理就要考虑线程安全和队列的问题,这个大家有时间看看 Message Queue,就会有更深的了解。


    二、观察者模式实现

    2.1、主题Subject

    首先定义一个观察者数组,并实现增、删及通知操作。它的职责很简单,就是定义谁能观察,谁不能观察,用Vector是线程同步的,比较安全,也可以使用ArrayList,是线程异步的,但不安全。

    public class Subject {
    
        //观察者数组
        private Vector<Observer> oVector = new Vector<>();
    
        //增加一个观察者,相当于观察者注册
        public void addObserver(Observer observer) {
            this.oVector.add(observer);
        }
    
        //删除一个观察者
        public void deleteObserver(Observer observer) {
            this.oVector.remove(observer);
        }
    
        //通知所有观察者,主题有变化时通知观察者
        public void notifyObserver() {
            for(Observer observer : this.oVector) {
                observer.response();
            }
        }
    
    }

     2.2、具体主题

    继承Subject类,在这里实现具体业务,在具体项目中,该类会有很多变种。

    public class ConcreteSubject extends Subject {
    
        //具体业务
        public void doSomething() {
            //...
    
            System.out.println("具体目标发生改变...");
            System.out.println("--------------");
            super.notifyObserver();
        }
    
    }

    2.3、抽象观察者Observer

    观察者一般是一个接口,每一个实现该接口的实现类都是具体观察者。

    public interface Observer {
       //响应
        public void response();
    }

    2.4、具体观察者

    实现Observer接口。

    //具体观察者1
    class ConcreteObserver1 implements Observer {
        public void response() {
            System.out.println("具体观察者1作出反应!");
        }
    }
    
    //具体观察者1
    class ConcreteObserver2 implements Observer {
        public void response() {
            System.out.println("具体观察者2作出反应!");
        }
    }
    ​

    2.5、ObserverPattern的main方法

    首先创建一个被观察者,然后定义一个观察者,将该被观察者添加到该观察者的观察者数组中,进行测试。

    public class ObserverPattern {
    
        public static void main(String[] args) {
            //创建一个主题
            ConcreteSubject subject = new ConcreteSubject();
            //定义一个观察者
            Observer observer = new ConcreteObserver();
            //注册观察者
            subject.addObserver(observer);
            //开始活动
            subject.doSomething();
        }
    
    }

    输出结果:

    具体目标发生改变... --------------

    具体观察者1作出反应!

    具体观察者2作出反应!


    三、Java中的观察者模式

    在 Java 中,通过 java.util.Observable 类和 java.util.Observer 接口定义了观察者模式,只要实现它们的子类就可以编写观察者模式实例。

    3.1、Observable类

    Observable 类是抽象目标类,它有一个 Vector 向量,用于保存所有要通知的观察者对象,下面来介绍它最重要的 3 个方法。

    • void addObserver(Observer o) 方法:用于将新的观察者对象添加到向量中。

    • void notifyObservers(Object arg) 方法:调用向量中的所有观察者对象的 update() 方法,通知它们数据发生改变。通常越晚加入向量的观察者越先得到通知。

    • void setChange() 方法:用来设置一个 boolean 类型的内部标志位,注明目标对象发生了变化。当它为真时,notifyObservers() 才会通知观察者。

    3.2、Observer 接口

    Observer 接口是抽象观察者,它监视目标对象的变化,当目标对象发生变化时,观察者得到通知,并调用 void update(Observable o,Object arg) 方法,进行相应的工作。

    3.3、利用 Observable 类和 Observer 接口实现原油期货的观察者模式实例

    分析:当原油价格上涨时,空方伤心,多方局兴;当油价下跌时,空方局兴,多方伤心。本实例中的抽象目标(Observable)类在 Java 中已经定义,可以直接定义其子类,即原油期货(OilFutures)类,它是具体目标类,该类中定义一个 SetPriCe(float price) 方法,当原油数据发生变化时调用其父类的 notifyObservers(Object arg) 方法来通知所有观察者;另外,本实例中的抽象观察者接口(Observer)在 Java 中已经定义,只要定义其子类,即具体观察者类(包括多方类 Bull 和空方类 Bear),并实现 update(Observable o,Object arg) 方法即可。图 5 所示是其结构图
     

    原油期货的观察者模式实例的结构图
    原油期货的观察者模式实例的结构图

     程序代码如下:

    package net.biancheng.c.observer;
    
    import java.util.Observer;
    import java.util.Observable;
    
    public class CrudeOilFutures {
        public static void main(String[] args) {
            OilFutures oil = new OilFutures();
            Observer bull = new Bull(); //多方
            Observer bear = new Bear(); //空方
            oil.addObserver(bull);
            oil.addObserver(bear);
            oil.setPrice(10);
            oil.setPrice(-8);
        }
    }
    
    //具体目标类:原油期货
    class OilFutures extends Observable {
        private float price;
    
        public float getPrice() {
            return this.price;
        }
    
        public void setPrice(float price) {
            super.setChanged();  //设置内部标志位,注明数据发生变化
            super.notifyObservers(price);    //通知观察者价格改变了
            this.price = price;
        }
    }
    
    //具体观察者类:多方
    class Bull implements Observer {
        public void update(Observable o, Object arg) {
            Float price = ((Float) arg).floatValue();
            if (price > 0) {
                System.out.println("油价上涨" + price + "元,多方高兴了!");
            } else {
                System.out.println("油价下跌" + (-price) + "元,多方伤心了!");
            }
        }
    }
    
    //具体观察者类:空方
    class Bear implements Observer {
        public void update(Observable o, Object arg) {
            Float price = ((Float) arg).floatValue();
            if (price > 0) {
                System.out.println("油价上涨" + price + "元,空方伤心了!");
            } else {
                System.out.println("油价下跌" + (-price) + "元,空方高兴了!");
            }
        }
    }

    程序运行结果如下:

    油价上涨10.0元,空方伤心了!

    油价上涨10.0元,多方高兴了!

    油价下跌8.0元,空方高兴了!

    油价下跌8.0元,多方伤心了!

    3.4、Java中手写线程安全的观察者模式

    先来定下一种场景,我每个月都会在微信上收到包租婆的房租单,假设包租婆是被观察者,我是观察者,租客我把联系方式留给包租婆这就是一个注册过程,每个月月初,包租婆都会通知我们交租(被观察者变化通知观察者)。

    package com.hs.demo.design;
    
    import java.util.Observable;
    import java.util.Observer;
    
    public class JavaObserverPattern
    {
        public static void main(String[] args)
        {   
            Exploiter exploiter = new Exploiter();
    
            TheOppressed theOppressed1 = new TheOppressed("打工仔1");
            TheOppressed theOppressed2 = new TheOppressed("打工仔2");
            TheOppressed theOppressed3 = new TheOppressed("打工仔3");
    
            //房东给打工仔(观察者)注册
            exploiter.addObserver(theOppressed1);
            exploiter.addObserver(theOppressed2);
            exploiter.addObserver(theOppressed3);
    
            //(被观察者)房东发信息了,通知所有观察者交房租
            exploiter.postChange("打工仔们快来交房租啦~~");
    
        }
    }
    
    //Observer抽象观察者
    class TheOppressed implements Observer
    {
        public String name;
        public TheOppressed(String name){
            this.name = name;
        }
    
        @Override
        public void update(Observable o, Object arg) {
            System.out.println(name +" 收到要交租信息");
        }
    }
    
    //Observable抽象目标类
    class Exploiter extends Observable
    {
    
        public void postChange(String content)
        {
            setChanged();
            notifyObservers(content);
        }
    
    }

    输出结果:

    打工仔3 收到要交租信息
    打工仔2 收到要交租信息
    打工仔1 收到要交租信息

    其实在JDK9之后,Observer 这些都已经被废弃了,主要因为它

    • 不可序列化,Observable是个类,而不是一个接口,没有实现Serializable,所以,不能序列化和它的子类

    • 没有线程安全,方法可以被其子类覆盖,并且事件通知可以以不同的顺序并且可能在不同的线程上发生。

    • 可以使用PropertyChangeEvent和PropertyChangeListener,它是java.beans包下的类

    手写线程安全的观察者模式

    其实我们从上面很容易看出来,多观察者需要串行调用,被观察者发生动作,观察者要作出回应,如果观察霆太多,而且处理时间长怎么办?用异步,也许你会脱口而出,那么,异步的处理就要考虑到线程安全和队列的问题。

    就是刚刚同样的场景,如果房东先发了一条涨租200,后来又发了一条,收房租(当然要多准备200),假设延迟性是非常的大的情况下,我们不可能单线程串行一直等,太费性能了,开了多线程的情况下,那么就会出现问题,可能某人会先收到交房租,这样就乱了。

    现实中有好多这种并发场景,一个或者多个线程,要等待另一组线程执行完成后,才能继续执行的问题,jdk已的com.util.concurrent下为我们提供了很多多线程同步的类,我们可以使用 CountDownLatch来保证被观察者的多个消息之间是有先后顺序的。

    总结:

    观察者模式主要是对象的解耦,将观察者与被观察者之间完全隔离。jdk提供的默认观察者Observer/Observable在多线程下有安全性问题,需要自己手写,JDK9之后已经废弃了。


    参考链接:

    深入理解设计模式(八):观察者模式

    重学设计模式——线程安全的观察者模式 

    更多相关内容
  • 设计模式(二)————观察者模式

    千次阅读 多人点赞 2021-10-15 16:20:31
    观察者模式可以说是JDK中使用最多的模式之一,这个模式可以让你的对象随时随地的了解想要知道的情况,你还可以让某个对象在运行时决定是否要继续通知;观察者模式的定义为: 定义对象间一种一对多的依赖关系,使得当...

    引言

    观察者模式可以说是JDK中使用最多的模式之一,这个模式可以让你的对象随时随地的了解想要知道的情况,你还可以让某个对象在运行时决定是否要继续通知;观察者模式的定义为:

    定义对象间一种一对多的依赖关系,使得当每一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新

    从定义就可以看出,观察者模式主要就是两部分:主题(Subject)和观察者(Observer)

    为了更清楚的了解观察者模式,下面将会用案例说明观察者模式;

    天气预报项目

    今天一个新的项目交到了你的手上,这个项目是一个天气预报公司的,他们想要

    • 将每天测量到的温度,湿度,气压等等以公告的形式发布出去
    • 设计开放型 API,便于其他第三方也能接入气象站获取数据
    • 而且天气预报最基本的要求是准时,不能开始下雨了才把下雨的预报发出来,所以很重要的一点是:每当天气预报更新的时候,要实时通知给第三方;

    通过需求分析可以提炼出关键一点:公布天气信息的“布告板”可以有多个,这些布告板全部从天气预报公司获取天气信息;
    大致是下图的意思:
    在这里插入图片描述
    再加上实时更新的需求,就是对标观察者模式;
    上面图可以等同于下面这个:
    在这里插入图片描述
    所以只需要确定好观察者模式的两个主要组成:主题(Subject)观察者(Observer)就好了;

    很明显,主题对象就是天气预报公司,观察者就是一系列第三方网站(的布告板)

    接下来就是如何用方法将观察者和主题联系起来呢?
    对于观察者来说,需要的方法就是一个:

    • 接受主题的输入(update)

    对于主题来说,需要以下功能:

    • registerObserver() 注册
    • removeObserver() 移除
    • notifyObservers() 通知注册的用户

    那么就可以简单尝试画出UML类图了:
    在这里插入图片描述
    大致就是这样,Subject是主题的接口,Observer是观察者的接口,
    可能你会觉得上面明明就说的那么简单,怎么这一下子多了好几个东西
    其实这样子的代码耦合度更低,而且思路非常简单,下面就来通过代码实现一下就明白了;


    主题:

    // 主题接口
    public interface Subject {
        public void registerObserver(Observer o); // 注册观察者
        public void removeObserver(Observer o); // 移除观察者
        public void notifyObserver(); // 通知观察者
    }
    
    // 实现主题接口,该类为天气预报公司
    import java.util.ArrayList;
    
    public class WeatherData implements Subject {
        private ArrayList<Observer> observers; // 观察者数组,存放所有观察者
        private float temperature; // 温度
        private float humidity; // 湿度
        private float pressure; // 压力
        public WeatherData() {
            observers = new ArrayList<>();
        }
        // 注册观察者
        @Override
        public void registerObserver(Observer o) {
            observers.add(o);
        }
        // 移除观察者
        @Override
        public void removeObserver(Observer o) {
            int i = observers.indexOf(o);
            if (i >= 0) {
                observers.remove(o);
            }
        }
        // 通知观察者
        @Override
        public void notifyObserver() {
            for (var i : observers) {
                i.update(this.temperature, this.humidity, this.pressure);
            }
        }
        // 信息更新
        public void measurementsChanged() {
            notifyObserver();
        }
        // 设置天气
        public void setMeasurements(float temperature, float humidity, float pressure) {
            this.temperature = temperature;
            this.humidity = humidity;
            this.pressure = pressure;
            measurementsChanged(); // 设置完成天气就已经改变了
        }
    }
    


    观察者:

    // 观察者
    public interface Observer {
        public void update(float temp, float humidity, float pressure); // 更新布告板
        public void display(); // 展示布告板
    }
    
    // 天气预报公司自己的布告板
    public class CurrentConditionsDisplay implements Observer{
        private float temperature; // 温度
        private float humidity; // 湿度
        private float pressure; // 压力
        @Override
        public void update(float temp, float humidity, float pressure) {
            this.temperature = temp;
            this.humidity = humidity;
            this.pressure = pressure;
            display();
        }
    
        @Override
        public void display() {
            System.out.println("当前温度:" + this.temperature +
                    "当前湿度:" + this.humidity + "当前压力:" + this.pressure);
        }
    }
    
    // 百度网站的温度布告板
    public class BaiDuDisplay implements Observer{
        private float temperature; // 温度
        private float humidity; // 湿度
        private float pressure; // 压力
        @Override
        public void update(float temp, float humidity, float pressure) {
            this.temperature = temp;
            this.humidity = humidity;
            this.pressure = pressure;
            display();
        }
        @Override
        public void display() {
            System.out.println("百度温度:" + this.temperature +
                    "百度湿度:" + this.humidity + "百度压力:" + this.pressure);
        }
    }
    

    还可以继续增加布告板,这里就列举这两个了;

    测试执行代码:

    public class WeatherStation {
        public static void main(String[] args) {
            WeatherData weatherData = new WeatherData();
            Observer current = new CurrentConditionsDisplay(); // 自己网站的观察者
            Observer baidu = new BaiDuDisplay(); // 百度观察者
            weatherData.registerObserver(current); // 注册观察者
            weatherData.registerObserver(baidu); // 注册观察者
            weatherData.setMeasurements(11, 22, 33);
        }
    }
    

    运行结果:

    当前温度:11.0当前湿度:22.0当前压力:33.0
    百度温度:11.0百度湿度:22.0百度压力:33.0
    

    其实一看代码,还是两大部分,所以对于观察者模式,主要思考的是主题和观察者的关系就可以了;

    使用了观察者模式后,代码有以下好处:

    • 观察者模式设计后,会以集合的方式来管理用户(Observer),包括注册,移除和通知
    • 增加观察者(即成一个新的公告板),就不需要去修改核心类 WeatherData 的代码,遵守 ocp (开闭)原则

    Java内置观察者模式

    JDK中提供了 java.util.Observable 实现类和 java.util.Observer 接口,这是Java内置的观察者模式,可以直接来用,先简单对比介绍一下:

    • Observable 的作用和地位等价于前面的Subject
    • Observable 是类,不是接口,类中已经实现了核心的方法 ,即管理 Observer 的方法 add… delete … notify…
    • Observer 接口的作用等价于前面的 Observer接口, 都有update
    • Observable类 和 Observer接口 的使用方法和前面讲过的一样,只是 Observable 是类,通过继承来实现观察者模式

    下面我将用内置观察者模式支持来重写一下上面的代码实现相同的功能;

    主题:

    import java.util.Observable;
    
    // 直接继承Observable类
    public class WeatherData extends Observable {
        private float temperature; // 温度
        private float humidity; // 湿度
        private float pressure; // 压力
        // 温度改变通知观察者
        public void measurementsChanged() {
            setChanged(); // 确定已经改变
            notifyObservers();
        }
        // 设置温度
        public void setMeasurements(float temperature, float humidity, float pressure) {
            this.temperature = temperature;
            this.humidity = humidity;
            this.pressure = pressure;
            measurementsChanged();
        }
        public float getTemperature() {
            return temperature;
        }
        public float getHumidity() {
            return humidity;
        }
        public float getPressure() {
            return pressure;
        }
    }
    


    观察者:

    // 天气预报公司自己的布告板
    import java.util.Observable;
    import java.util.Observer;
    
    // 实现了Observer接口
    public class CurrentConditionsDisplay implements Observer{
        private float temperature; // 温度
        private float humidity; // 湿度
        private float pressure; // 压力
        public void display() {
            System.out.println("当前温度为:" + this.temperature + " 当前湿度为:"
                    + this.humidity + " 当前压力为:" + this.pressure);
        }
        @Override
        public void update(Observable o, Object arg) {
            if (o instanceof WeatherData) {
                WeatherData weatherData = (WeatherData) o;
                this.temperature = weatherData.getTemperature();
                this.humidity = weatherData.getHumidity();
                this.pressure = weatherData.getPressure();
                display();
            }
        }
    }
    
    // 百度网站的温度布告板
    import java.util.Observable;
    import java.util.Observer;
    
    // 实现了Observer接口
    public class BaiDuDisplay implements Observer {
        private float temperature; // 温度
        private float humidity; // 湿度
        private float pressure; // 压力
        public void display() {
            System.out.println("百度温度为:" + this.temperature + " 百度湿度为:"
                    + this.humidity + " 百度压力为:" + this.pressure);
        }
        @Override
        public void update(Observable o, Object arg) {
            if (o instanceof WeatherData) {
                WeatherData weatherData = (WeatherData) o;
                this.temperature = weatherData.getTemperature();
                this.humidity = weatherData.getHumidity();
                this.pressure = weatherData.getPressure();
                display();
            }
        }
    }
    

    测试执行代码:

    public class WeatherStation {
        public static void main(String[] args) {
            WeatherData weatherData = new WeatherData(); // 主题
            CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(); // 观察者
            BaiDuDisplay baiDuDisplay = new BaiDuDisplay(); // 百度观察者
            weatherData.addObserver(currentConditionsDisplay); // 增添观察者
            weatherData.addObserver(baiDuDisplay);// 增添观察者
            weatherData.setMeasurements(11, 22, 33);
        }
    }
    

    运行结果:

    百度温度为:11.0 百度湿度为:22.0 百度压力为:33.0
    当前温度为:11.0 当前湿度为:22.0 当前压力为:33.0
    

    是不是有很多相同的地方,归根结底都是使用的观察者模式,所以只要知道观察者模式由什么组成,什么时候用,那么你就真正了解了观察者模式;

    但是设计模式可不是随便看看这俩代码就能会用的,这也是设计模式不好学的一点,还是需要大量的代码练习去体会,最后就能灵活运用;

    注:在JDK中JavaBeans和Swing都实现了观察者模式,感兴趣可以尝试一下;

    总结

    总结一下观察者模式:

    • 观察者模式定义了对象之间一对多的关系
    • 主题通过一个共同的接口来更新观察者
    • 观察者和主题之间用松耦合的方式结合,主题不知道观察者的细节,只知道观察者实现了观察者接口
    • 当有多个观察者时,不能依赖特定的通知次序

    最后在这里展示一下观察者模式的UML类图:
    在这里插入图片描述

    在这篇文章中的例子的代码只是为了展示观察者模式,但是并不是最优的代码,一个好的代码可能要用到多种设计模式,这也是设计模式的一个难点;
    设计模式的学习没有什么技巧,只能在敲代码的过程中不断去体会,可能某一天你就会不自觉的使用设计模式,还是要多敲代码多踩坑多思考,希望我们一起努力!!

    展开全文
  • 观察者模式2.1 源码2.2 结构3. Android中的观察者模式 1. 前言 观察者模式是在代码框架中使用比较高的一个设计模式,常常又叫做订阅/发布模式。而通过这个设计模式通常我们就可以做到代码的解耦。 在现实生活中,...

    1. 前言

    观察者模式是在代码框架中使用比较高的一个设计模式,常常又叫做订阅/发布模式。而通过这个设计模式通常我们就可以做到代码的解耦

    在现实生活中,比如当我们订阅了Android官方资讯后,用户就可以收到来自这些网站的推荐消息。在这个场景中就是发布/订阅模式。而这种观察行为通常是一个被观察者,多个观察者。通过观察者模式可以实现一种一对多的关系,使得当被观察者的状态发生改变的时候,所有的观察者都可以得到通知,并作出相应的更新操作。

    2. 观察者模式

    JavaObserverObservableJDK内置实现的,当我们需要用到观察者模式的时候就可以考虑实现相关的方法。比如下面的案例。

    首先定义一观察者,需要实现Observer接口:

    // 观察者
    static class Person implements Observer{
    
        private String name;
        public Person(String n){
            this.name = n;
        }
    
        @Override
        public void update(Observable o, Object arg) {
            System.out.println(this.name+": ==> " + arg);
        }
    }
    

    以及对应的被观察者对象,继承自Observable类:

    // 被观察者
    static class Message extends Observable{
    
        public void messageHasChanged(String content){
            setChanged();
            notifyObservers(content);
        }
    }
    

    最后我们就可以简单的测试了:

    public static void main(String[] args) {
        Message message = new Message(); // 被观察者
        Person person1 = new Person("张三"); // 观察者
        Person person2 = new Person("李四");
        Person person3 = new Person("王五");
    
        // 将二者关联
        message.addObserver(person1);
        message.addObserver(person2);
        message.addObserver(person3);
    
        // 发布消息
        message.messageHasChanged("这是一个测试消息!");
    }
    

    测试结果:
    在这里插入图片描述
    可以看到是按照注册的倒序来更新消息。当然至于为什么会是这样,其实在源码中是将原本的观察者对象拷贝到一个数组中,然后数组从最后一个位置向前遍历得来的。接下来不妨看看Observer接口和Observable类的源代码。

    2.1 源码

    Observer接口非常简单,就一个未实现的方法update

    public interface Observer {
        void update(Observable o, Object arg);
    }
    

    Observable类中定义了一个容器数组Vector来存储观察者对象Observer,在添加观察者对象的时候会对观察者做一个非空的判断。且定义了一个布尔类型的私有变量changed来标识是否发生改变。整个代码逻辑比较简单,可以发现主要的逻辑在notifyObservers方法中。在进行遍历通知观察者的时候,在该方法中首先对当前对象加了一个synchronized锁,主要是为了判断当前被观察者对象是否改变,如果没有改变就返回。否则就将所有注册的观察者装载到一个Object数组中(装载后将changed变量重置为false),然后逆序调用每个Observer对象的update方法。

    public class Observable {
        private boolean changed = false;
        private Vector<Observer> obs;
    
        public Observable() {
            obs = new Vector<>();
        }
    
        public synchronized void addObserver(Observer o) {
            if (o == null)
                throw new NullPointerException();
            if (!obs.contains(o)) {
                obs.addElement(o);
            }
        }
    
        public synchronized void deleteObserver(Observer o) {
            obs.removeElement(o);
        }
    
        public void notifyObservers() {
            notifyObservers(null);
        }
    
        public void notifyObservers(Object arg) {
            Object[] arrLocal;
    
            synchronized (this) {
                if (!changed)
                    return;
                arrLocal = obs.toArray();
                clearChanged();
            }
    
            for (int i = arrLocal.length-1; i>=0; i--)
                ((Observer)arrLocal[i]).update(this, arg);
        }
    
    	...
    }
    

    2.2 结构

    为了直观的Idea中查看到类图,不妨在一个包下面仿造上述两个类,然后再定义测试方法。最后使用Idea的插件Sketch lt!来进行plantuml生成,最终看到结构。

    定义为:

    package com.weizu;
    
    public interface CustomObserver {
        void update(CustomObservable o, Object msg);
    }
    
    public class CustomObservable {
    
        private List<CustomObserver> mObservers;
    
        public CustomObservable(){
            mObservers = new ArrayList<CustomObserver>();
        }
    
        public synchronized void addObserver(CustomObserver o) {
            if (o == null)
                throw new NullPointerException();
            if (!mObservers.contains(o)) {
                mObservers.add(o);
            }
        }
    
        public void notifyObservers(Object msg) {
            for (CustomObserver mObserver : mObservers) {
                mObserver.update(this, msg);
            }
        }
    }
    

    测试用例:

    public class Demo {
    
        // 观察者
        static class Person implements CustomObserver{
    
            private String name;
            public Person(String n){
                this.name = n;
            }
    
            public void update(CustomObservable o, Object arg) {
                System.out.println(this.name+": ==> " + arg);
            }
        }
    
        // 被观察者
        static class Message extends CustomObservable{
    
            public void messageHasChanged(String content){
                notifyObservers(content);
            }
        }
    
        public static void main(String[] args) {
            Message message = new Message(); // 被观察者
            Person person1 = new Person("张三"); // 观察者
            Person person2 = new Person("李四");
            Person person3 = new Person("王五");
    
            // 将二者关联
            message.addObserver(person1);
            message.addObserver(person2);
            message.addObserver(person3);
    
            // 发布消息
            message.messageHasChanged("这是一个测试消息!");
        }
    }
    

    然后使用下面的工具来生成weizu.plantuml文件:
    在这里插入图片描述

    最后,拷贝weizu.plantuml文件内容到http://www.plantuml.com/,即可看见下图:
    在这里插入图片描述

    不难发现其实上面的类图中涉及到了四种不同类型的角色,分别是被观察者、观察者、具体被观察者以及具体观察者对象。

    在上面的代码中不难发现一件事情,那就是使用观察者模式确实可以降低代码的耦合关系。其主要思想不难看出主要是在被观察者中遍历观察者,后调用抽象方法update。也就是说当观察者对象很多的时候,通知的发布就是一件非常耗时的事情了,可能回影响到程序的效率。

    且在观察者和被观察者之间的关系也仅是抽象的调用关系,所以在这里依赖于抽象而没有依赖于具体的实现,符合依赖倒置原则。

    3. Android中的观察者模式

    在使用ListView添加数据的时候,会调用AdapternotifyDataSetChanged()方法。其实这里也是观察者模式的运用,不妨来简单看下源码。比如此时自定义的Adapter继承自ArrayAdapter,然后从这个自定义类的notifyDataSetChanged方法开始追踪:
    在这里插入图片描述
    从上面的流程中可以清晰的看到,其实最终的观察者模式,且被观察者对象是Adapter中的mDataSetObservable对象,该对象继承自Observable对象。从Observable定义的mObservers为泛型类型可以看出观察者的对象这里为了通用性,直接申明了泛型。

    那么,被观察者是在什么地方进行观察者的注册的呢?在Adapter中的观察者又是什么对象?带着这两个问题,这里继续看源码。

    因为前面提到了,被观察这对象是Adapter中的mDataSetObservable对象,为了找到在什么地方注册的观察者,所以我们需要找到被观察者的注册方法,也就是:

    public abstract class Observable<T> {
        protected final ArrayList<T> mObservers = new ArrayList<T>();
    
        public void registerObserver(T observer) {
            if (observer == null) {
                throw new IllegalArgumentException("The observer is null.");
            }
            synchronized(mObservers) {
                if (mObservers.contains(observer)) {
                    throw new IllegalStateException("Observer " + observer + " is already registered.");
                }
                mObservers.add(observer);
            }
        }
        ...
    }
    

    那么,不妨按住Ctrl+鼠标左键进行追踪:
    在这里插入图片描述

    可以看到前面我们看过的类BaseAdapter中调用了这个方法,所以这里切换到这个方法中:

    public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
    	public void registerDataSetObserver(DataSetObserver observer) {
            mDataSetObservable.registerObserver(observer);
        }
        ...
    }
    

    使用类似的方法对类BaseAdapter中的registerDataSetObserver方法进行追踪,但其实没有结果了。所以这里尝试换个对象,因为适配器更新的对象为ListView的每个Item,按道理讲观察者对象应该就是这些Item。所以这里找到ListViewsetAdapter方法,这里因为我本地并没有下载相关的源码配置,所以这里androidxref来查看源码。比如ListView

    // ListView.java
    public void setAdapter(ListAdapter adapter) {
        // 如果有Adapter,且观察者存在就注销观察者 
        if (mAdapter != null && mDataSetObserver != null) {
            mAdapter.unregisterDataSetObserver(mDataSetObserver);
        }
    
        ...
        super.setAdapter(adapter);
    
        if (mAdapter != null) {
            ...
    
            // 创建观察者,并注册到被观察者对象
            mDataSetObserver = new AdapterDataSetObserver();
            mAdapter.registerDataSetObserver(mDataSetObserver);
    
            mRecycler.setViewTypeCount(mAdapter.getViewTypeCount());
    
            ...
        }
        ...
    }
    

    观察上面代码,我们知道其实观察者在这里也就是AdapterDataSetObserver这个类的实例。不妨再次在网站上查找,这个类定义在AbsListView.java中,为一个内部类:

    class AdapterDataSetObserver extends AdapterView<ListAdapter>.AdapterDataSetObserver {
        @Override
        public void onChanged() {
            super.onChanged();
            if (mFastScroll != null) {
                mFastScroll.onSectionsChanged();
            }
        }
    
        @Override
        public void onInvalidated() {
            super.onInvalidated();
            if (mFastScroll != null) {
                mFastScroll.onSectionsChanged();
            }
        }
    }
    

    可以看到出现了前面在DataSetObservable被观察者类中的遍历调用onChanged方法,继续追踪很有意思,mFastScroll.onSectionsChanged()方法如下:

    // FastScroller.java
    private Adapter mListAdapter;
    public void onSectionsChanged() {
    	mListAdapter = null;
    }
    

    所以说其实主要的处理方法其实在其父类中,这里继续追踪父类AdapterView<ListAdapter>.AdapterDataSetObserver中的onChanged()

    在这里插入图片描述
    也就是观察者调用的onChanged方法即为其触发方法。在这个方法中,会请求重新绘制ListView界面。

    到这里是否就完了?明天继续!


    References

    • 《Android源码设计模式》
    展开全文
  • C++观察者模式

    千次阅读 2021-11-22 21:55:48
    C++观察者模式   当对象间存在一对多关系时,则使用观察者模式(observer pattern)。比如,当一个对象被修改时,则会自动通知发依赖它的对象。观察者模式属于行为型模式。   Observer模式是应用最多、影响最广...

    C++观察者模式

      当对象间存在一对多关系时,则使用观察者模式(observer pattern)。比如,当一个对象被修改时,则会自动通知发依赖它的对象。观察者模式属于行为型模式。

      Observer模式是应用最多、影响最广的设计模式之一,因为Observer的一个实例Model/View/Control(MVC)结构在系统开发架构设计中有着很重要的地位和意义,MVC实现了业务逻辑和表示层的解耦。在MFC(微软基础类库)中,Doc/View(文档视图结构)提供了实现MVC的框架结构。

      在GOF的《设计模式:可复用面向对象软件的基础》一书中对观察者模式是这样定义的:定义对象的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。当一个对象发生了变化,关注它的对象就会得到通知;这种交互也成为发布-订阅(publish-subscribe)。

       MVC框架是模型-视图-控制器的缩写,一种软件设计典范。用一种业务逻辑、数据、显示界面分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能。在一个逻辑的图形化用户界面的结构中MVC分层有助于管理复杂的应用程序,因为可以在一个时间内专注的关注一个方面,可以在不依赖业务逻辑的情况下专注于视图设计,同时也将应用程序的测试更加容易。

    介绍

    意图:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并被自动更新。

    主要解决:一个对象状态改变并给其它对象通知的问题,而且要考虑到易用和低耦合,保证高度的协作。

    何时使用:一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知,进行广播通知。

    如何解决:使用面向对象技术,可以将这种依赖关系弱化。

    关键代码:在抽象类里有一个arrayList存放观察者们。

    应用实例:1、拍卖的时候,拍卖师观察最高价格,然后通知给其它竞价者竞价。2、西游记里面悟空请求菩萨降服红孩儿,菩萨洒了一地水找来一个老乌龟,这个老乌龟就是观察者(菩萨是被观察者),他观察菩萨这个动作。

    优点:1、观察者和被观察者是抽象耦合的。2、建立一套触发机制。

    缺点:1、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。2、如果在观察者和观察目标之间有循环依赖的话,观察目标会触发它们之间进行循环调用,可能导致系统崩溃。3、观察者模式没有相应的机制让观察者知道所观察的目标对象是怎么发生变化的,而仅仅只是知道观察目标发生了变化。

    使用场景

    • 一个抽象模型有两个方面,其中一个方面发依赖于另外一个方面。将这些方面封装在独立的对象中使它们可以各自独立地改变和复用。
    • 一个对象的改变将导致其它一个或多个对象发生改变,而不知道具体有多少对象将发生改变,可以降低对象之间的耦合度。
    • 一个对象必须通知其他对象,而并不知道这些对象是谁。
    • 需要在系统中创建一个触发链,A对象的行为将影响B对象,B对象的行为将影响C对象……,可以使用观察者模式创建一种链式触发机制。

    注意事项:1、应避免循环引用。2、如果顺序执行,某一观察者错误会导致系统卡壳,一般采用异步方式(多线程)。

    示例1

      对同一组数据进行统计分析的时候,我们希望能够提供多种形式的表示(例如以表格形式进行显示、柱状图统计显示、百分比统计显示等)。这些表示都依赖于同一组数据,我们当然需要当数据改变的时候,所有统计的显示都能同时改变、Observer模式就是解决了这一个问题。

    UML类图

    效果图

    • Subject(目标)
      • 目标知道它的观察者,可以有任意多个观察者观察用一个目标。
      • 提供注册和删除观察者对象的接口。
    • Observer(观察者)
      • 为所有观察目标的观察者对象提供一个公共的更新接口。
    • ConcreteSubject(具体目标)
      • 将有关状态的情况广播给各ConcreteObserver对象。
    • ConcreteObserver(具体观察者)
      • 维护一个指向ConcreteSubject对象的指针。用于当具体观察者初始化时直接存入ConcreteSubject对象(初始化就订阅ConcreteSubject主题)。
      • 存储有有关状态,这些状态应与目标的状态保持一致。
      • 实现Observer公共更新接口以便使自身状态和目标状态保持一致。

    观察者模式按照以下方式进行协作:

    1. 当ConcreteSubject发生任何可能导致其观察者与其本身状态不一致的改变时,它将通知它的各个观察者。
    2. 在得到一个具体目标的改变通知后,ConcreteObserver对象可收到目标对象的信息。ConcreteObserver使用这些信息使它的状态和目标对象的状态保持一致。

    代码实现:

    #include <iostream>
    #include <list>
    using std::cout;
    using std::endl;
    using std::cin;
    
    
    
    class Observer
    	{
    	public:
    		virtual ~Observer() {};
    		virtual void Update(int) = 0;
    	};
    
    
    
    
    	class Subject
    	{
    	public:
    		virtual ~Subject() {};
    		virtual void Attach(Observer*) = 0;
    		virtual void Detach(Observer*) = 0;
    		virtual void Notify() = 0;
    	};
    
    
    	class ConcreteObserver : public Observer
    	{
    	private:
    		Subject *_pSubject;
    
    	public:
    		ConcreteObserver(Subject* pSubject) :_pSubject(pSubject)
    		{
    			//在目标中注册当前观察者(此处的观察者是广义上的观察者,目标并不知道具体谁要观察它,目标只进行广播即可)
    			this->_pSubject->Attach(this);
    			cout << "I'm the observer \" 1 \".\n";
    		}
    
    		void Update(int value) override
    		{
    			cout << "ConcreteObserver get the update.New State:" << value << endl;
    		}
    	};
    
    
    
    	class ConcreteObserver2 : public Observer
    	{
    	private:
    		Subject *_pSubject;
    
    	public:
    		ConcreteObserver2(Subject* pSubject) :_pSubject(pSubject)
    		{
    			//在目标中注册当前观察者(此处的观察者是广义上的观察者,目标并不知道具体谁要观察它,目标只进行广播即可)
    			this->_pSubject->Attach(this);
    			cout << "I'm the observer \" 2 \".\n";
    		}
    
    		void Update(int value) override
    		{
    			cout << "ConcreteObserver2 get the update.New State:" << value << endl;
    		}
    	};
    
    
    	class ConcreteSubject :public Subject
    	{
    	private:
    		std::list<Observer*> _pObserverList;
    		int _iState;
    	public:
    		void SetState(int state)
    		{
    			_iState = state;
    		}
    
    		void Attach(Observer* pObserver) override
    		{
    			_pObserverList.push_back(pObserver);
    		}
    
    
    		void Detach(Observer* pObserver) override
    		{
    			_pObserverList.remove(pObserver);
    		}
    
    
    		void Notify() override
    		{
    			auto begin = _pObserverList.begin();
    			auto end = _pObserverList.end();
    			while (begin != end)
    			{
    				(*begin)->Update(_iState);
    				begin++;
    			}
    		}
    	};
    
    int main()
    {
    	//创建目标
    	ConcreteSubject *pSubject = new ConcreteSubject();
    
    	//创建观察者
    	Observer *pObserver = new ConcreteObserver(pSubject);
    	Observer *pObserver2 = new ConcreteObserver2(pSubject);
    
    	//改变当前状态
    	pSubject->SetState(2);
    
    	//广播给所有广义上的观察者
    	pSubject->Notify();
    
    	//去除某个观察者
    	pSubject->Detach(pObserver);
    
    	//改变当前状态
    	pSubject->SetState(3);
    
    	//重新广播
    	pSubject->Notify();
    
    
    	//结束,释放对象
    	delete pObserver;
    	delete pObserver2;
    	delete pSubject;
    	return 0;
    }
    

    输出结果(vs2017):

    效果图

    示例2(高阶版)

    #include <iostream>
    #include <list>
    #include <string>
    using std::cout;
    using std::endl;
    using std::cin;
    
    
    
    /*
    观察者模式有许多具有类似含有的不同术语,比如主题也成为发布者,观察者通常称为订阅者。
    动词“观察”、“倾听”或“跟踪”通常表示相同的意思。
    */
    
    
    
    class IObserver
    {
    public:
    	virtual ~IObserver() {}
    	virtual void Update(const std::string &messageFromSubject) = 0;
    };
    
    
    
    class ISubject
    {
    public:
    	virtual ~ISubject() {}
    	virtual void Attach(IObserver *observer) = 0;
    	virtual void Detach(IObserver *observer) = 0;
    	virtual void Notify() = 0;
    };
    
    
    
    //具体目标拥有一些重要的状态,并在状态更改时通知观察者
    class Subject : public ISubject
    {
    private:
    	std::list<IObserver *> _listObserver;
    	std::string _messgae;
    public:
    	virtual ~Subject()
    	{
    		cout << "Goodbye,I was the Subject.\n";
    	}
    
    
    	//定义订阅管理方法
    	void Attach(IObserver* observer) override
    	{
    		_listObserver.push_back(observer);
    	}
    
    	void Detach(IObserver* observer) override
    	{
    		_listObserver.remove(observer);
    	}
    
    	void Notify() override
    	{
    		std::list<IObserver *>::iterator begin = _listObserver.begin();
    		HowManyObserver();
    		while (begin != _listObserver.end())
    		{
    			(*begin)->Update(_messgae);
    			++begin;
    		}
    	}
    
    	void CreateMessage(std::string message = "Empty")
    	{
    		this->_messgae = message;
    		Notify();
    	}
    
    
    	void HowManyObserver()
    	{
    		cout << "There are " << _listObserver.size() << " observers in the list\n";
    	}
    
    
    	/*
    	通常的来说,订阅逻辑知识主题真正能做的事情的一小部分。
    	主题通常拥有一些重要的业务逻辑,每当重要的事情即将发生(或者发生之后)时触发通知方法。
    	*/
    	void SomeBusinessLogic()
    	{
    		this->_messgae = "change message message";
    		Notify();
    		cout << "I'm about to do some thing important.\n";
    	}
    };
    
    
    class Observer :public IObserver
    {
    private:
    	std::string _messageFromSubject;
    	Subject &_subject;
    	static int _staticNumber;
    	int _number;
    public:
    	Observer(Subject &subject) :_subject(subject)
    	{
    		this->_subject.Attach(this);
    		cout << "Hi,I'm the Observer \"" << ++Observer::_staticNumber << "\".\n";
    		this->_number = Observer::_staticNumber;
    	}
    
    	~Observer()
    	{
    		cout << "Goodbye, I was the Observer \"" << this->_number << "\".\n";
    	}
    
    
    	void Update(const std::string &messageFromSubject) override
    	{
    		this->_messageFromSubject = messageFromSubject;
    		PrintInfo();
    	}
    
    	void RemoveMeFromTheList()
    	{
    		this->_subject.Detach(this);
    		cout << "Observer \"" << this->_number << "\" removed from the list.\n";
    	}
    
    	void PrintInfo()
    	{
    		cout << "Observer \"" << this->_number << "\": a new message is aviilable -->" << this->_messageFromSubject << "\n";
    	}
    
    };
    
    int Observer::_staticNumber = 0;
    
    
    void ClientCode()
    {
    	Subject * subject = new Subject();
    	Observer *observer1 = new Observer(*subject);
    	Observer *observer2 = new Observer(*subject);
    	Observer *observer3 = new Observer(*subject);
    	Observer *observer4;
    	Observer *observer5;
    
    	subject->CreateMessage("hello world! :D");
    	observer3->RemoveMeFromTheList();
    
    	subject->CreateMessage("The weather is hot today! :p");
    	observer4 = new Observer(*subject);
    
    	observer2->RemoveMeFromTheList();
    	observer5 = new Observer(*subject);
    	observer4->RemoveMeFromTheList();
    	observer1->RemoveMeFromTheList();
    
    	delete observer5;
    	delete observer4;
    	delete observer3;
    	delete observer2;
    	delete observer1;
    	delete subject;
    }
    
    int main()
    {
    	ClientCode();
    	return 0;
    }
    

    输出结果(vs2017):

    效果图

    参考文章

    https://www.runoob.com/design-pattern/observer-pattern.html

    https://www.cnblogs.com/carsonzhu/p/5770253.html

    展开全文
  • 观察者模式及其应用场景

    千次阅读 2022-04-24 08:18:02
    观察者模式(Observer Design Pattern),也叫做发布订阅模式(Publish-Subscribe Design Pattern)、模型-视图(Model-View)模式、源-监听器(Source-Listener)模式、从属者(Dependents)模式。指在对象之间定义...
  • 观察者模式又叫做发布-订阅(Publish/Subscribe)模式,模型-视图( Model/View)模式、源-监听器( Source/Listener)模式或从属者(Dependents)模式。观察者模式是一种对象行为型模式。
  • 详细介绍了观察者模式,通过一个军队游戏实例实现了观察者模式
  • 设计模式——观察者模式

    千次阅读 2021-03-11 14:16:02
    生活中,许多事物不是单独存在的,其中一个事物发生变化可能会导致一个或多个其他事物的行为也发生变化。例如:公众号的博主与...一、观察者模块的定义与优缺点观察者模式(Observer Pattern):定义对象间的一种一对...
  • java设计模式之观察者模式

    千次阅读 多人点赞 2021-06-04 08:13:39
    不利于维护,也不是动态加入 无法在运行时动态的添加第三方 (新浪网站) 违反ocp原则=>观察者模式 观察者模式 观察者模式介绍 概念其实很简单,两个主体,一个观察者,一个被观察者,当被观察者发生变化时,观察者会...
  • C++行为型模式-实现观察者模式

    千次阅读 多人点赞 2021-07-27 08:53:23
    一、观察者模式基本概念 二、改进观察者模式 参考文献: 【1】
  • 大话设计模式——观察者模式

    千次阅读 2022-04-10 20:45:31
    } } 观察者模式 观察者模式,又叫做发布-订阅(Publish/Subscribe)模式。 观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,...
  • Kotlin - 改良观察者模式

    千次阅读 2022-03-13 22:22:51
    Kotlin - 改良观察者模式 Kotlin - 改良策略模式 Kotlin - 改良迭代器模式 Kotlin - 改良责任链模式 Kotlin - 改良装饰者模式 一、前言 观察者模式 作用:定义了一个一对多的依赖关系,让一个或多个观察者对象...
  • 一、观察者模式简介、 二、观察者模式适用场景、 三、观察者模式优缺点、 四、观察者模式代码示例、 1、被观察者、 2、观察者、 3、通知类、 4、测试类、 五、JDK 中的观察者模式支持类、 1、Observable、 2、...
  • 游戏设计模式-观察者模式

    千次阅读 2022-04-09 21:47:52
    观察者模式可以解决这件事情。 首先,我们先定义两个类,分别是观察者和被观察者。 观察者: class Observer { friend class Subject; public: Observer() :next(nullptr), previous(nullptr) {} void ...
  • 单例模式 单例模式 单例模式(Singleton Pattern)是 Java 中最常见的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 单例模式涉及到一个单一的类,该类负责创建自己的对象,...
  • 观察者模式 | C#实现

    千次阅读 2022-04-12 22:41:35
    什么是观察者模式观察者模式(Observer Pattern)又被称为发布-订阅(Publish/Subscribe)模式。 该模式描述了对象间一对多的依赖关系,当一个对象状态发生改变时,其依赖对象都会得到通知并自动更新。 发生改变...
  • 观察者模式

    千次阅读 2019-05-07 22:45:49
    观察者模式 在说观察者模式之前,我们先来说下设计模式的几大原则: 单一职责原则 开放关闭原则 里氏代换原则 依赖倒转原则 接口隔离法则 迪米特法则 观察者模式: 又称发布–订阅模式(有时又称为模型(Model)-...
  • 什么是观察者模式

    千次阅读 2021-11-01 18:40:00
    观察者模式 观察者模式,也被称为发布订阅模式,是一种行为型设计模式,也是在实际的开发中用得比较多的一种模式,当对象间存在一对多关系时,就可以使用观察者模式。定义对象间的一种一对多的依赖关系,当一个对象...
  • 23种设计模式——观察者模式

    千次阅读 2022-04-26 20:18:37
    观察者(Observer)模式本质:触发联动
  • 设计模式之游戏--观察者模式详解

    千次阅读 2022-01-07 15:19:57
    为了解决上述诸如此类的问题,我们引入的观察者模式。 定义 它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当这个主题对象在状态变化时,会通知所有的观察者对象并使它们能够自动更新。...
  • Java观察者模式讲解及代码实现

    千次阅读 2022-03-03 15:58:50
    观察者模式又叫做发布-订阅模式,是对象间的一对多的关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新 组成 抽象主题角色(Subject) 也叫抽象目标类,抽象主题知道自己的观察者有...
  • 发布订阅模式与观察者模式

    万次阅读 多人点赞 2019-03-29 18:25:12
    设计模式并非是软件开发的专业术语,实际上,“模式”最早诞生于建筑学。 设计模式的定义是:在面向对象软件设计过程中针对特定问题的简洁而优雅的解决方案。通俗一点说,设计模式是在某种场合下对某个问题的一种...
  • kotlin——观察者模式

    千次阅读 2022-03-29 22:04:53
    * 1、观察者模式管理类 */ class ObserverManager : SubjectListener { /** * 观察者集合 */ private val list = ArrayList<ObserverListener>() override fun add(observerListener: ...
  • 观察者模式(Observer模式)

    千次阅读 2021-11-26 14:43:02
    例如,某种商品的物价上涨时会导致部分商家高兴,而消费伤心;还有,当我们开车到交叉路口时,遇到红灯会停,遇到绿灯会行。这样的例子还有很多,例如,股票价格与股民、微信公众号与微信用户、气象局的天气预报与...
  • 观察者模式 目标者对象和观察者对象有相互依赖的关系,观察者对某个对象的状态进行观察,如果对象的状态发生改变,就会通知所有依赖这个对象的观察者, 目标者对象Subject,拥有方法:添加 / 删除 / 通知Observer...
  • js观察者模式和发布订阅者模式

    千次阅读 2022-01-26 15:50:04
    一、观察者模式的理解 观察者模式:一个对象(称为subject)维持一系列依赖于它的对象(称为observer),将有关状态的任何变更自动通知给它们(观察者)。 二、发布/订阅模式的理解 发布/订阅模式:基于一个主题/...
  • js设计模式之观察者模式

    千次阅读 2021-10-23 14:45:23
    什么是观察者模式观察者模式是一对多的一种依赖关系,让多个观察者对象同时监听某一个主体对象。这个主体发生状态的时候。会通知所有的观察者对象,自动更新自己的状态。 而发布订阅者模式,则不同。发布订阅...
  • Spring中的观察者模式

    千次阅读 2021-07-29 14:07:34
    今天来聊聊Spring中的观察者模式前言一、观察者设计模式中涉及到的角色二、使用设计模式的优缺点优点缺点三、示例代码四、Spring中的观察者设计模式 前言 今天来看一看什么是观察者模式,在现实生活中,观察者模式...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 333,879
精华内容 133,551
关键字:

观察者模式