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

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

    观察者模式–浅谈


    在说观察者模式之前,我们先来说下设计模式的几大原则:
    单一职责原则
    开放关闭原则
    里氏代换原则
    依赖倒转原则
    接口隔离法则
    迪米特法则

    观察者模式
    又称发布–订阅模式(有时又称为模型(Model)-视图(View)模式、源-收听者(Listener)模式或从属者模式)。观察者模式完美的将观察者和被观察者的对象分离开,举个例子,用户界面作为观察者,业务数据作为被观察者,两者之间存在“观察”的逻辑,用户界面观察业务数据的变化,当被观察者(业务数据)发生变化时,观察者(用户界面)就会观察到到变化,并作出相应的响应。

    实现
    实现观察者模式的时候要注意,观察者和被观察对象之间的互动关系不能体现成类之间的直接调用,否则就将使观察者和被观察对象之间紧密的耦合起来,从根本上违反面向对象的设计的原则。无论是观察者“观察”观察对象,还是被观察者将自己的改变“通知”观察者,都不应该直接调用。
    以上,我们可以看出,观察者模式主要用于解耦,将观察者和被观察者解耦,让两者之间没有依赖或者依赖关系很小。

    应用
    Android四大组件之一的BroadcastReceiver,实际上也是一个典型的观察者模式,通过sendBroadcast发送广播时候,只有注册了相应的IntentFilter的BroadcastReceiver对象才会收到这条广播消息,进而做出响应。
    另外,现在比较流行的第三方框架很多也是用的观察者模式,例如EventBus、RxJava、RxAndroid、otto等等。在这里就不拿其中一个作为例子解析。

    角色说明
    Subject(抽象主题):又叫抽象被观察者,把所有观察者对象的引用保存到一个集合里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
    ConcreteSubject(具体主题):又叫具体被观察者,将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。
    Observer (抽象观察者):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
    ConcrereObserver(具体观察者):实现抽象观察者定义的更新接口,当得到主题更改通知时更新自身的状态。

    具体实现例子
    让我们用父亲通知儿子做事的例子来说明
    1、创建抽象观察者—Observer
    定义一个接到通知的更新方法,即儿子们接到通知后的反应

    public interface Observer {
        public void updata(String msg);
    }
    

    2、创建具体观察着(即儿子们)—ConcrereObserver

    public class SonSeaObserver implements Observer {
    
        private String name;
    
        public SonSea(String name) {
            this.name = name;
        }
    
        @Override
        public void updata(String msg) {
            System.out.println(name+"收到了消息:"+msg+"后开始傲娇拒绝");
        }
    }
    
    public class SonZhenObserver  implements Observer {
    
        private String name;
    
        public SonZhen(String name) {
            this.name = name;
        }
    
        @Override
        public void updata(String msg) {
            System.out.println(name+"收到了消息:"+msg+"屁颠屁颠照做了");
        }
    }
    

    3、创建抽象主题----Subject
    即抽象被观察者,定义添加、删除、通知等方法

    public interface Observable {
    
        void add(Observer observer);
    
        void remove(Observer observer);
    
        void notify(String msg);
    }
    

    4、创建具体主题—ConcreteSubject
    即具体被观察者(父亲),发布通知

    public class FatherObservable  implements Observable {
    
        private List<Observer> sonList = new ArrayList<>();
    
        @Override
        public void add(Observer observer) {
            sonList.add(observer);
        }
    
        @Override
        public void remove(Observer observer) {
            sonList.remove(observer);
        }
    
        @Override
        public void notify(String msg) {
            for (Observer observer : sonList){
                observer.updata(msg);
            }
        }
    }   
    

    5、具体测试

    private void testObserver(){
            Observable fatherOb = new FatherOb();
            SonSea sonSea = new SonSea("海海");
            SonZhen sonZhen = new SonZhen("大正");
    
            fatherOb.add(sonSea);
            fatherOb.add(sonZhen);
    
            fatherOb.notify("去扑街啦");
        }
    

    6、理解
    实际上,JDK内部也内置了Observable(抽象被观察者),Observer(抽象观察者)这两个类,我们也可以直接拿来用,其代码如下:

    public interface Observer {//(抽象观察者
        //只定义了一个update方法
        void update(Observable o, Object arg);
    }
    
    public class Observable {//抽象被观察者
        private boolean changed = false;//定义改变状态,默认为false
        private final ArrayList<Observer> observers;//定义一个观察者list
    
        public Observable() {//构造函数,初始化一个观察者list来保存观察者
            observers = new ArrayList<>();
        }
        //添加观察者,带同步字段的,所以是线程安全的
        public synchronized void addObserver(Observer o) {
            if (o == null)
                throw new NullPointerException();
            if (!observers.contains(o)) {
                observers.add(o);
            }
        }
    
        //删除观察者
        public synchronized void deleteObserver(Observer o) {
            observers.remove(o);
        }
    
        //通知所以观察者,无参数
        public void notifyObservers() {
            notifyObservers(null);
        }
    
         //通知所有观察者,带参数
        public void notifyObservers(Object arg) {
    
            Observer[] arrLocal;
            //加synchronized字段,保证多线程下操作没有问题
            synchronized (this) {
                if (!hasChanged())//这里做了是否发生改变的判断,是为了防止出现无意义的更新
                    return;
    
                arrLocal = observers.toArray(new Observer[observers.size()]);//ArrayList转换成一个临时的数组,这样就防止了通知,添加,移除同时发生可能导致的异常
                clearChanged();///清除改变状态,设置为false
            }
            //遍历逐一通知
            for (int i = arrLocal.length-1; i>=0; i--)
                arrLocal[i].update(this, arg);
        }
    
        //清楚所有观察者
        public synchronized void deleteObservers() {
            observers.clear();
        }
    
        //设置被观察者为改变状态,设置为true
        protected synchronized void setChanged() {
            changed = true;
        }
    
        //清除改变状态,设置为false
        protected synchronized void clearChanged() {
            changed = false;
        }
    
        //返回当前的改变状态
        public synchronized boolean hasChanged() {
            return changed;
        }
    
        //观察者数量
        public synchronized int countObservers() {
            return observers.size();
        }
    }
    

    优点

    • 解除观察者与主题之间的耦合。让耦合的双方都依赖于抽象,而不是依赖具体。从而使得各自的变化都不会影响另一边的变化。
    • 易于扩展,对同一主题新增观察者时无需修改原有代码。

    缺点

    • 依赖关系并未完全解除,抽象主题仍然依赖抽象观察者。
    • 使用观察者模式时需要考虑一下开发效率和运行效率的问题,程序中包括一个被观察者、多个观察者,开发、调试等内容会比较复杂,而且在Java中消息的通知一般是顺序执行,那么一个观察者卡顿,会影响整体的执行效率,在这种情况下,一般会采用异步实现。
    • 可能会引起多余的数据通知。
    展开全文
  • 设计模式之观察者模式Java版本实现和UML类设计图
  • 观察者模式demo

    2017-11-24 13:29:51
    观察者模式demo 观察者模式demo 观察者模式demo 观察者模式demo
  • 设计模式混编:观察者模式+中介者模式

    千次阅读 多人点赞 2021-01-29 16:20:00
    针对变化万千的业务需求,采用合适的设计模式是可以轻松应对的。本文将探索多种优秀设计模式的混编来解决复杂场景的问题,实现1+1>2的效果。应用实践离不开基础,所以文章将以基本概念、设...

    针对变化万千的业务需求,采用合适的设计模式是可以轻松应对的。

    本文将探索多种优秀设计模式的混编来解决复杂场景的问题,实现1+1>2的效果。应用实践离不开基础,所以文章将以基本概念、设计初衷出发,逐层讲解混编设计模式的落地。

    观察者模式


      应用背景


    在软件系统设计中,我们经常会有这样的需求:如果一个对象的状态发生改变,某些与它相关的对象也要随之做出相应的变化。比如我们会有以下几个场景诉求:

    • 如果一个用户关注了一个公众号,那便会收到公众号发来的消息。

    • 用户的一个点击事件,会触发界面背景颜色的变更、收到一个后台消息等。

    由于关联事件的广泛应用,所以观察者模式也是在项目中经常使用的模式之一。

      基本介绍

    观察者模式包含观察目标和观察者两类对象,一个目标可以有任意数目的与之相依赖的观察者,一旦观察目标的状态发生改变,所有的观察者都将得到通知。

    基于上述应用场景的表达,我们可以来看一下该模式的定义。观察者模式(Observer Pattern) 也叫做发布订阅模式(Publish/Subscribe),定义对象间一种一对多的依赖关系,使得每当一个对象改变状态时,则所有依赖于它的对象都会得到通知并被自动更新(Define a one-to-many dependency between objects so that when one object changes state,all its dependents are notified and updated automatically)。

    观察者模式作为一种对象行为型模式,解决的问题依然是两个关联对象间(观察者和被观察者)的耦合。

    其通用的类图如下所示:

    在观察者模式中,会存在几个角色:

    • Subject 被观察者

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

    • Observer观察者

      观察者接收到消息后,通过update操作进行处理。

    • ConcreteSubject具体被观察者

      在基于被观察者自己通用的业务逻辑上,同时可以定义对哪些事件进行通知。

    • ConcreteObserver具体观察者

      消息接收后,有着不同的处理逻辑。

    观察模式核心代码:

    //被观察者
    public abstract class Subject {
      //定义一个观察者数组
      private Vector<Observer> obsVector = new Vector<Observer>();
      //增加一个观察者
      public void addObserver(Observer o){
      this.obsVector.add(o);
      }
        //删除一个观察者
      public void delObserver(Observer o){
      this.obsVector.remove(o);
      }
        //通知所有观察者
      public void notifyObservers(){
            for(Observer o:this.obsVector){
                o.update();
            }
      }
    }
    
    
    //观察者
    public interface Observer {
      //更新方法
      public void update();
    }
    

      优缺点分析


    优点

    • 观察者和被观察者之间抽象耦合

      在扩展能力上,不管是增加观察者还是被观察者都是比较简单的。

    • 建立一套触发机制

      在设计理念上,我们任务每个类的职责都是单一的,即单一职责原则。那么,通过观察者模式我们可以将多个类串联起来,形成一个触发链,构建一个触发机制。

    缺点

    在应用观察者模式时,我们需要对开发效率和运行效率特别注意。比如,通用的消息通知形式是以顺序执行的,如果一个观察者出现异常,将会导致整体的执行异常,同时处理时间也严格与每一个观察者节点有关,是累加的关系。因此在复杂场景下,需要考虑采用异步的方式。

      使用场景

    事件多级触发场景、跨系统间的消息交换场景等。

      注意事项

    在使用观察者模式时,有一个广播链的问题需要特别注意到。

    • 广播链问题

      在设计观察者模式时,会存在这样的一种考虑,一个对象具有双重身份,即又是观察者,也是被观察者。这样,消息就可以在多个节点间传播(和责任链模式有一点点类似,都是建立传播链)。但是该链式结构一旦建立,逻辑就比较复杂,可维护性也是非常差的。根据经验建议,一个观察者模式中,最多出现一个对象既是观察者也是被观察者,即消息最多转发一次,建立三个节点的传播链,这样是比较好控制的。

    中介模式


      应用背景

    DataX是集团内被广泛使用的离线数据同步工具/平台,实现包括 MySQL、Oracle、HDFS、Hive、OceanBase、HBase、OTS、ODPS 等各种异构数据源之间高效的数据同步功能。

    DataX其实相当于一个中介,从数据源读取数据,同步写入到目标端,数据源不再需要维护到目标端的同步作业,只需要与 DataX 通信即可。DataX体现了中介者模式的思想。

      基本介绍

    中介者模式(Mediator Pattern):用一个中介对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使其耦合松散, 而且可以独立地改变它们之间的交互(Define an object that encapsulates how a set of objectsinteract.Mediator promotes loose coupling by keeping objects from referring to each other explicitly,and it lets you vary their interaction independently)。

    显然,中介模式解决的问题依旧是耦合关系。

    其通用的类图如下:

    中介模式下存在三个角色,主要包括:

    • Mediator 抽象中介者

      抽象中介者角色定义统一的接口,用于各同事角色之间的通信。

    • Concrete Mediator 具体中介者

      通过协调各同事角色实现协作行为,因此它必须依赖于各个同事角色。

    • Colleague 同事角色

      每个同事角色都会维持者一个对抽象中介者类的引用,可以在需要和其他同事对象通信时,先与中介者通信,通过中介者来间接完成与其他同事类的通信。此外,同事类的行为包括两种,一种是改变自身状态、处理自己行为的自发行为;另一种则是依赖中介者才能完成的依赖行为。

    中介者模式的核心是引入了中介者类,那么中介者类主要承担了两个责任,其一是中转作用,通过中介者提供的中转作用,各个同事对象就不再需要显式引用其他同事;其二是协调作用,中介者可以更进一步的对同事之间的关系进行封装和分离,而同事类仅需保持一致的和中介者进行交互即可。

    中介模式核心代码:

    //抽象中介者类
    public abstract class Mediator {
        //定义同事类
        protected ConcreteColleague1 c1;
        protected ConcreteColleague2 c2;
        //通过getter/setter方法把同事类注入进来
        public ConcreteColleague1 getC1() {
            return c1;
        }
        public void setC1(ConcreteColleague1 c1) {
            this.c1 = c1;
        }
        public ConcreteColleague2 getC2() {
            return c2;
        }
        public void setC2(ConcreteColleague2 c2) {
            this.c2 = c2;
        }
        //中介者模式的业务逻辑
        public abstract void doSomething1();
        public abstract void doSomething2();
    }
    //中介者类
    public class ConcreteMediator extends Mediator {
        @Override
        public void doSomething1() {
            //调用同事类的方法, 只要是public方法都可以调用
            super.c1.selfMethod1();
            super.c2.selfMethod2();
        }
        public void doSomething2() {
            super.c1.selfMethod1();
            super.c2.selfMethod2();
        }
    }
    


      优缺点分析

    优点

    中介者模式减少了类间的相互依赖,它用中介者和同事的一对多交互代替了原来同事之间的多对多交互,一对多关系更容易理解、维护和扩展,将原本难以理解的网状结构转换成相对简单的星型结构。

    缺点

    中介者模式内中介者会膨胀得很大, 而且包含着大量同事类之间的交互细节,原本N个对象直接的相互依赖关系转换为中介者和同事类的依赖关系,同事类越多,中介者的逻辑就越复杂。

      使用场景

    中介者模式适用于多个对象之间紧密耦合的情况,紧密耦合的标准是在类图中出现了蜘蛛网状结构。中介者模式可以将蜘蛛网状结构转变为星型结构,使原本复杂混乱的关系变得清晰且简单。

    事件触发器最佳实践


      事件触发器任务

    今天,我们的任务是来模拟一个事件触发器。有一个产品,它有多个触发事件,它产生的时候会触发一个创建事件,在修改的时候触发修改事件,删除的时候触发删除事件,初始化的时候要触发一个onCreat事件,修改的时候触发onChange事件,双击的时候又触发onDoubleClick事件,例如Button按钮。

    根据基本任务需求来看,对于多事件动作,我们可以采用工厂方法模式。此外,考虑我们的产品(如GUI设计)经常会使用复制粘贴操作,所以我们也是有一个很明显的设计模式可以使用-原型模式。结合到权限问题,也就是我们的产品并不是谁想产生就产生的,否则触发创建事件的门槛也太容易和简单了。因此,在设计中,我们的产品只能由工厂类创建,而不能被其他对象通过new方式创建,那么在这里,单来源调用(Single Call)方法可以解决。

    由此我们可以看一下UML图:

    实现逻辑比较简单,在此可以注意一下isCreateProduct方法和Product的构造函数为何传递进来了一个工厂对象ProductManager。没错,正是解决产品生产的权限问题。

    在工厂类ProductManager中定义了一个私有变量isPermittedCreate,该变量只有在工厂类的createProduct函数中才能设置为true。在创建产品的时候,产品类Product的构造函数要求传递工厂对象,然后判断是否能够创建产品,即使你想使用类似这样的方法:

    Productp=new Product(newProductManager(),"abc");
    

    也是不能创建出产品的。所以说在产品类中限制了两个生产条件,第一是必须是当前有效的工厂,第二就是拿到了生产资格。所以单来源调用的定义就很明显了,我们将这种一个对象只能由固定的对象初始化的方法叫做单来源调用。

    //Product产生一个新的产品
    public Product(ProductManager manager, String name) {
        //允许建立产品
        if (manager.isCreateProduct()) {
            canChanged = true;
            this.name = name;
        }
    }
    

    产生事件的对象有了之后,我们就触发事件了。与此同时,也是要考虑事件的处理对象的。自然而然,观察者模式就可以出场了。那么,UML可以升级为如下所示:

    观察者模式的设计框架已基本显现,被观察者是Product产品,观察者是EventDispatch事件分发器,具体事件处理我们后面讲,消息的传播对象是ProductEvent事件。接下来,我们看一下具体代码细节。

    /**
     * @author la.lda
     * @date 2020-12-07
     */
    public class Product implements Cloneable {
        //产品名称
        private String name;
        //是否可以属性变更
        private boolean canChanged = false;
        //产生一个新的产品
        public Product(ProductManager manager, String name) {
            //允许建立产品
            if (manager.isCreateProduct()) {
                canChanged = true;
                this.name = name;
            }
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            if (canChanged) {
                this.name = name;
            }
        }
        @Override
        public Product clone() {
            Product p = null;
            try {
                p = (Product) super.clone();
            } catch (CloneNotSupportedException e) {
                e.printStackTrace();
            }
            return p;
        }
    }
    
    /**
     * @author la.lda
     * @date 2020-12-07
     */
    public enum ProductEventType {
        //新建一个产品
        NEW_PRODUCT(1),
        //删除一个产品
        DEL_PRODUCT(2),
        //修改一个产品
        EDIT_PRODUCT(3),
        //克隆一个产品
        CLONE_PRODUCT(4);
        private int value = 0;
        ProductEventType(int value) {
            this.value = value;
        }
        public int getValue() {
            return this.value;
        }
    }
    

    ProductEventType定义了4个事件类型,分别是新建、修改、删除以及克隆。

    /**
     * @author la.lda
     * @date 2020-12-07
     */
    public class ProductEvent extends Observable {
        //事件起源
        private Product source;
        //事件的类型
        private ProductEventType type;
        //传入事件的源头, 默认为新建类型
        public ProductEvent(Product p) {
            this(p, ProductEventType.NEW_PRODUCT);
        }
        //事件源头以及事件类型
        public ProductEvent(Product p, ProductEventType type) {
            this.source = p;
            this.type = type;
            //事件触发
            notifyEventDispatch();
        }
        //获得事件的始作俑者
        public Product getSource() {
            return source;
        }
        //获得事件的类型
        public ProductEventType getEventType() {
            return this.type;
        }
        //通知事件处理中心
        private void notifyEventDispatch() {
            super.addObserver(EventDispatch.getEventDispatch());
            super.setChanged();
            super.notifyObservers(source);
        }
    }
    

    在产品事件对象中,增加了一个私有方法notifyEventDispatch,该方法的作用就是增加事件观察者,并在有参构造进行初始化时被调用,通知观察者。

    前面说到,我们采用工厂模式对多事件进行处理,如新建、删除等。而现在产品和事件作为两个独立的对象,如何将两者进行组合关联呢?那工厂类就需要新增一个功能,组合产品和事件,产生有价值的产品事件。

    ProductManager的代码如下:

    /**
     * @author la.lda
     * @date 2020-12-07
     */
    public class ProductManager {
        //是否可以创建一个产品
        private boolean isPermittedCreate = false;
        //建立一个产品
        public Product createProduct(String name) {
            //首先修改权限,允许创建
            isPermittedCreate = true;
            Product product = new Product(this, name);
            //产生一个创建事件
            new ProductEvent(product, ProductEventType.NEW_PRODUCT);
            return product;
        }
        //废弃一个产品
        public void abandonProduct(Product product) {
            //销毁一个产品,例如删除数据库记录
            new ProductEvent(product, ProductEventType.DEL_PRODUCT);
            product = null;
        }
        //修改一个产品
        public void editProduct(Product product, String name) {
            //修改后产品
            new ProductEvent(product, ProductEventType.EDIT_PRODUCT);
            product.setName(name);
        }
        //获得是否可以创建一个产品
        public boolean isCreateProduct() {
            return isPermittedCreate;
        }
        //克隆一个产品
        public Product clone(Product product) {
            //产生克隆事件
            new ProductEvent(product, ProductEventType.CLONE_PRODUCT);
            return product.clone();
        }
    }
    

    可以看出,每个事件动作下面都增加了事件产生机制,通过组合的形式,产品和事件在扩展性上都有很强的提升。

    讲述完被观察者以及广播消息后,我们来看一下下游节点-观察者。刚才说到,我们构建了一个事件分发器,为什么要有如此的设计呢?可以想象的到,对于一个事件,自然会有多个处理者,而且一个处理者处理完之后还可能通知其他的处理者。在扩展能力上,我们有新处理者加入之后是否会影响到现有的设计框架呢?因此,本文另外一个设计模式-中介模式就可以上场了。我们将EventDispatch作为中介者,事件的分发器,而事件的处理这都是具体的同事类,它们有独立的处理产品事件的逻辑。当然,我们既然有了一个中心控制,也是可以增加一个功能-权限管理,即EventDispatch能决定观察者能处理什么事件,不能处理什么事件。

    因此,EventDispatch有三个职责:

    • 事件的观察者

    • 事件分发器

    • 事件处理者管理员

    那么,我们现在可以完成最后一轮设计结构上的升级了。

    事件分发器EventDispatch代码:

    import java.util.ArrayList;
    import java.util.Observable;
    import java.util.Observer;
    /**
     * @author la.lda
     * @date 2020-12-07
     */
    public class EventDispatch implements Observer {
        //单例模式
        private final static EventDispatch dispatch = new EventDispatch();
        //事件消费者
        private ArrayList<EventCustomer> customerList = new ArrayList<EventCustomer>();
        //不允许生成新的实例
        private EventDispatch() {
        }
        //获得单例对象
        public static EventDispatch getEventDispatch() {
            return dispatch;
        }
        @Override
        public void update(Observable o, Object arg) {
            //事件的源头
            Product product = (Product) arg;
            //事件
            ProductEvent event = (ProductEvent) o;
            //处理者处理,这里是中介者模式的核心,可以是很复杂的业务逻辑
            for (EventCustomer e : customerList) {
                //处理能力是否匹配
                for (EventCustomType t : e.getCustomType()) {
                    if (t.getValue() == event.getEventType().getValue()) {
                        e.exec(event);
                    }
                }
            }
        }
        //注册事件处理者
        public void registerCustomer(EventCustomer customer) {
            customerList.add(customer);
        }
    }
    

    在EventDispatch里使用ArrayList存储所有的事件处理者,然后在update方法中使用了比较简单for循环完成业务逻辑的判断,其中第一层轮询事件处理者,第二层则轮询事件处理者所能处理的事件类型。只要有事件处理者的处理类型和事件类型相匹配,则调用事件处理方法exec,进入具体事件处理者的特定逻辑中。

    在这里我们对事件处理者也抽象了一层,抽象类EventCustomer定义了事件处理者通用的能力,也标示出事件处理者必须具备的行为,即定义每个处理者的处理类型。当然,这里也是能够处理多个事件的。

    import java.util.ArrayList;
    /**
     * @author la.lda
     * @date 2020-12-07
     */
    public abstract class EventCustomer {
        //容纳每个消费者能够处理的级别
        private ArrayList<EventCustomType> customType = new ArrayList<EventCustomType>();
        //每个消费者都要声明自己处理哪一类别的事件
        public EventCustomer(EventCustomType type) {
            addCustomType(type);
        }
        //每个消费者可以消费多个事件
        public void addCustomType(EventCustomType type) {
            customType.add(type);
        }
        //得到自己的处理能力
        public ArrayList<EventCustomType> getCustomType() {
            return customType;
        }
        //每个事件都要对事件进行声明式消费
        public abstract void exec(ProductEvent event);
    }
    
    /**
     * @author la.lda
     * @date 2020-12-07
     */
    public enum EventCustomType {
        //新建立事件
        NEW(1),
        //删除事件
        DEL(2),
        //修改事件
        EDIT(3),
        //克隆事件
        CLONE(4);
        private int value = 0;
        EventCustomType(int value) {
            this.value = value;
        }
        public int getValue() {
            return value;
        }
    }
    

    可以看出,EventCustomType的定义与事件类型ProductEventType基本相同。当然采用一套类型也是可以的。但从长远上来说,个人建议还是区分出来,因为无法保证观察者只有一个消息广播来源,也可能在另一组被观察者上有其他的事件类型发生。

    接下来,定义三个具体的事件处理者,分别对不同事件类型进行业务逻辑处理。

    /**
     * @author la.lda
     * @date 2020-12-07
     */
    public class Senior extends EventCustomer {
        public Senior() {
            super(EventCustomType.EDIT);
            super.addCustomType(EventCustomType.CLONE);
        }
        @Override
        public void exec(ProductEvent event) {
            //事件的源头
            Product p = event.getSource();
            //事件类型
            ProductEventType type = event.getEventType();
            if (type.getValue() == EventCustomType.CLONE.getValue()) {
                System.out.println("高级专家处理事件:" + p.getName() + "克隆,事件类型=" + type);
            } else {
                System.out.println("高级专家处理事件:" + p.getName() + "修改,事件类型=" + type);
            }
        }
    }
    
    /**
     * @author la.lda
     * @date 2020-12-07
     */
    public class Middle extends EventCustomer {
        public Middle() {
            super(EventCustomType.DEL);
        }
        @Override
        public void exec(ProductEvent event) {
            //事件的源头
            Product p = event.getSource();
            //事件类型
            ProductEventType type = event.getEventType();
            System.out.println("中级专家处理事件:" + p.getName() + "销毁,事件类型=" + type);
        }
    }
    
    /**
     * @author la.lda
     * @date 2020-12-07
     */
    public class Primary extends EventCustomer {
        public Primary() {
            super(EventCustomType.NEW);
        }
        @Override
        public void exec(ProductEvent event) {
            //事件的源头
            Product p = event.getSource();
            //事件类型
            ProductEventType type = event.getEventType();
            System.out.println("初级专家处理事件:" + p.getName() + "诞生记,事件类型=" + type);
        }
    }
    

    最后,我们建立自己的场景,看一下执行情况。

    /**
     * @author la.lda
     * @date 2020-12-07
     */
    public class Client {
        public static void main(String[] args) {
            //获得事件分发中心
            EventDispatch dispatch = EventDispatch.getEventDispatch();
            dispatch.registerCustomer(new Senior());
            dispatch.registerCustomer(new Middle());
            dispatch.registerCustomer(new Primary());
            //建立一个原子弹生产工厂
            ProductManager factory = new ProductManager();
            //制造一个产品
            System.out.println("=====模拟创建产品事件========");
            System.out.println("创建一个嫦娥卫星5号");
            Product p = factory.createProduct("嫦娥卫星5号");
            //修改一个产品
            System.out.println("\n=====模拟修改产品事件========");
            System.out.println("把嫦娥卫星5号修改为嫦娥卫星6号");
            factory.editProduct(p, "嫦娥卫星6号");
            //再克隆一个原子弹
            System.out.println("\n=====模拟克隆产品事件========");
            System.out.println("克隆嫦娥卫星6号");
            factory.clone(p);
            //遗弃一个产品
            System.out.println("\n=====模拟销毁产品事件========");
            System.out.println("遗弃嫦娥卫星6号");
            factory.abandonProduct(p);
        }
    }
    

    我们的事件处理框架已经生效了,有行为,就产生事件,触发事件处理,三者都相互解耦相互独立,在扩展性上有很大的提升。如果想增加处理者,则建立一个继承EventCustomer的类,然后注册到EventDispatch,就可以进行事件处理了。

      触发器扩展

    回顾整个设计流程,感觉某些地方还是可以优化的。如果想扩展产品,也就是观察者想要观察多个产品,如何改进呢?

    在结合最开始所说,产品是采用单来源调用方式由工厂生产的,那么我们可以进行简单修正来实现产品的扩展性。

    /**
     * @author la.lda
     * @date 2020-12-07
     */
    public abstract class Product implements Cloneable {
        //产品名称
        private String name;
        //是否可以属性变更
        private boolean canChanged = false;
        //产品类型标示
        private String type;
        //产生一个新的产品
        public Product(ProductManager manager, String name, String type) {
            //允许建立产品
            if (manager.isCreateProduct()) {
                canChanged = true;
                this.name = name;
                this.type = type;
            }
        }
        ......
    }
    
    /**
     * @author la.lda
     * @date 12/13/20
     */
    public class ProductA extends Product {
        public ProductA(ProductManager manager, String name) {
            super(manager, name, "A");
        }
    }
    
    /**
     * @author la.lda
     * @date 12/13/20
     */
    public class ProductB extends Product {
        public ProductB(ProductManager manager, String name) {
            super(manager, name, "B");
        }
    }
    

    从代码结构上可知,抽象Product,以产品类型type来标示子类,工厂通过方法签名生产出不同产品类型的产品。由此,我们彻底完成了观察者、消息以及被观察者的解耦和扩展任务,就可以欢乐的写业务逻辑了。

    至此,我们以观察者模式和中介模式为主,采用多种经典设计模式,完成了一个可支持多事件分发、处理的事件触发器。

    设计模式混编总结


    事件触发框架的设计,结构清晰,扩展性良好,同时也运用了不同的设计模式。

    • 原型模式

      负责对象克隆和拷贝的功能。

    • 工厂方法模式

      负责生产和管理产品对象。

    • 观察者模式

      观察者模式解决了事件如何通知处理者的问题。

    • 中介模式

      中介者模式完美地处理了事件和处理者之间的复杂关系,解决多处理者之间的耦合关系,应对快速的业务变。

    当然,业务的变化也是无穷的,我们可基于该框架的局部进行不断升级和改进,融入更多的优秀设计模式,提高系统在稳定性、复用性以及扩展性方面的能力。

    参考书籍《设计模式之禅-设计模式混编》

    淘系技术部-行业与智能运营-全域营销

    我们战斗在阿里电商的核心地带,负责连接供需两端,支持电商营销领域的各类产品、平台和解决方案,其中包括聚划算、百亿补贴、天猫U先、天猫小黑盒、天猫新品孵化、品牌号等重量级业务。我们深度参与双11、618、99划算节等年度大促,不断挑战技术的极限! 团队成员背景多样,有深耕电商精研技术的老师傅,也有朝气蓬勃的小萌新,更有可颜可甜的小姐姐,期待具有好奇心和思考力的你的加入!

    【招聘岗位】Java工程师,数据研发工程师

    如果您有兴趣可将简历发至邮箱 dongang.lda@alibaba-inc.com 或者加作者微信 L-dongang~

    ✿  拓展阅读

    作者|李东昂(锂昂)

    编辑|橙子君

    出品|阿里巴巴新零售淘系技术

    展开全文
  • 接口实现C#观察者模式简单例子
  • 发布订阅模式与观察者模式

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

    背景

    设计模式并非是软件开发的专业术语,实际上,“模式”最早诞生于建筑学。

    设计模式的定义是:在面向对象软件设计过程中针对特定问题的简洁而优雅的解决方案。通俗一点说,设计模式是在某种场合下对某个问题的一种解决方案。如果再通俗一点说,设计模式就是给面向对象软件开发中的一些好的设计取个名字。

    这些“好的设计”并不是谁发明的,而是早已存在于软件开发中。一个稍有经验的程序员也许在不知不觉中数次使用过这些设计模式。GoF(Gang of Four–四人组,《设计模式》几位作者)最大的功绩是把这些“好的设计”从浩瀚的面向对象世界中挑选出来,并且给予它们一个好听又好记的名字。

    设计模式并不直接用来完成代码的编写,而是描述在各种不同情况下,要怎么解决问题的一种方案,他不是一个死的机制,他是一种思想,一种写代码的形式。每种语言对于各种设计模式都有他们自己的实现方式,对于某些设计模式来说,可能在某些语言下并不适用,比如工厂方法模式对于javascript。模式应该用在正确的地方。而哪些才算正确的地方,只有在我们深刻理解了模式的意图之后,再结合项目的实际场景才会知道。。

    模式的社区一直在发展。GoF在1995年提出了23种设计模式,但模式不仅仅局限于这23种,后面增加到了24种。在这20多年的时间里,也许有更多的模式已经被人发现并总结了出来,比如一些JavaScript 图书中会提到模块模式、沙箱模式等。这些“模式”能否被世人公认并流传下来,还有待时间验证。

    观察者模式(Observer Pattern)

    观察者模式定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知,并自动更新。观察者模式属于行为型模式,行为型模式关注的是对象之间的通讯,观察者模式就是观察者和被观察者之间的通讯。

    观察者模式有一个别名叫“发布-订阅模式”,或者说是“订阅-发布模式”,订阅者和订阅目标是联系在一起的,当订阅目标发生改变时,逐个通知订阅者。我们可以用报纸期刊的订阅来形象的说明,当你订阅了一份报纸,每天都会有一份最新的报纸送到你手上,有多少人订阅报纸,报社就会发多少份报纸,报社和订报纸的客户就是上面文章开头所说的“一对多”的依赖关系。

    发布订阅模式(Pub-Sub Pattern)

    其实24种基本的设计模式中并没有发布订阅模式,上面也说了,他只是观察者模式的一个别称。

    但是经过时间的沉淀,似乎他已经强大了起来,已经独立于观察者模式,成为另外一种不同的设计模式。

    在现在的发布订阅模式中,称为发布者的消息发送者不会将消息直接发送给订阅者,这意味着发布者和订阅者不知道彼此的存在。在发布者和订阅者之间存在第三个组件,称为消息代理或调度中心或中间件,它维持着发布者和订阅者之间的联系,过滤所有发布者传入的消息并相应地分发它们给订阅者。

    举一个例子,你在微博上关注了A,同时其他很多人也关注了A,那么当A发布动态的时候,微博就会为你们推送这条动态。A就是发布者,你是订阅者,微博就是调度中心,你和A是没有直接的消息往来的,全是通过微博来协调的(你的关注,A的发布动态)。

    观察者模式和发布订阅模式有什么区别?

    我们先来看下这两个模式的实现结构:
    模式结构

    观察者模式: 观察者(Observer)直接订阅(Subscribe)主题(Subject),而当主题被激活的时候,会触发(Fire Event)观察者里的事件。

    发布订阅模式: 订阅者(Subscriber)把自己想订阅的事件注册(Subscribe)到调度中心(Topic),当发布者(Publisher)发布该事件(Publish topic)到调度中心,也就是该事件触发时,由调度中心统一调度(Fire Event)订阅者注册到调度中心的处理代码。

    我们再来看下这两个模式的代码案例:(猎人发布与订阅任务)

    观察者模式:

        //有一家猎人工会,其中每个猎人都具有发布任务(publish),订阅任务(subscribe)的功能
    	//他们都有一个订阅列表来记录谁订阅了自己
    	//定义一个猎人类
    	//包括姓名,级别,订阅列表
    	function Hunter(name, level){
    		this.name = name
    		this.level = level
    		this.list = []
    	}
    	Hunter.prototype.publish = function (money){
    		console.log(this.level + '猎人' + this.name + '寻求帮助')
    	    this.list.forEach(function(item, index){
    	    	item(money)
    	    })
    	}
    	Hunter.prototype.subscribe = function (targrt, fn){
    		console.log(this.level + '猎人' + this.name + '订阅了' + targrt.name)
    	    targrt.list.push(fn)
    	}
    	
    	//猎人工会走来了几个猎人
    	let hunterMing = new Hunter('小明', '黄金')
    	let hunterJin = new Hunter('小金', '白银')
    	let hunterZhang = new Hunter('小张', '黄金')
    	let hunterPeter = new Hunter('Peter', '青铜')
    	
    	//Peter等级较低,可能需要帮助,所以小明,小金,小张都订阅了Peter
    	hunterMing.subscribe(hunterPeter, function(money){
    		console.log('小明表示:' + (money > 200 ? '' : '暂时很忙,不能') + '给予帮助')
    	})
    	hunterJin.subscribe(hunterPeter, function(){
    		console.log('小金表示:给予帮助')
    	})
    	hunterZhang.subscribe(hunterPeter, function(){
    		console.log('小金表示:给予帮助')
    	})
    	
    	//Peter遇到困难,赏金198寻求帮助
    	hunterPeter.publish(198)
    	
    	//猎人们(观察者)关联他们感兴趣的猎人(目标对象),如Peter,当Peter有困难时,会自动通知给他们(观察者)
    

    发布订阅模式:

        //定义一家猎人工会
    	//主要功能包括任务发布大厅(topics),以及订阅任务(subscribe),发布任务(publish)
    	let HunterUnion = {
    		type: 'hunt',
    		topics: Object.create(null),
    		subscribe: function (topic, fn){
    		    if(!this.topics[topic]){
    		      	this.topics[topic] = [];  
    		    }
    		    this.topics[topic].push(fn);
    		},
    		publish: function (topic, money){
    		    if(!this.topics[topic])
    		      	return;
    		    for(let fn of this.topics[topic]){
    		    	fn(money)
    		    }
    		}
    	}
    	
    	//定义一个猎人类
    	//包括姓名,级别
    	function Hunter(name, level){
    		this.name = name
    		this.level = level
    	}
    	//猎人可在猎人工会发布订阅任务
    	Hunter.prototype.subscribe = function (topic, fn){
    		console.log(this.level + '猎人' + this.name + '订阅了狩猎' + topic + '的任务')
    	    HunterUnion.subscribe(topic, fn)
    	}
    	Hunter.prototype.publish = function (topic, money){
    		console.log(this.level + '猎人' + this.name + '发布了狩猎' + topic + '的任务')
    	    HunterUnion.publish(topic, money)
    	}
    	
    	//猎人工会走来了几个猎人
    	let hunterMing = new Hunter('小明', '黄金')
    	let hunterJin = new Hunter('小金', '白银')
    	let hunterZhang = new Hunter('小张', '黄金')
    	let hunterPeter = new Hunter('Peter', '青铜')
    	
    	//小明,小金,小张分别订阅了狩猎tiger的任务
    	hunterMing.subscribe('tiger', function(money){
    		console.log('小明表示:' + (money > 200 ? '' : '不') + '接取任务')
    	})
    	hunterJin.subscribe('tiger', function(money){
    		console.log('小金表示:接取任务')
    	})
    	hunterZhang.subscribe('tiger', function(money){
    		console.log('小张表示:接取任务')
    	})
    	//Peter订阅了狩猎sheep的任务
    	hunterPeter.subscribe('sheep', function(money){
    		console.log('Peter表示:接取任务')
    	})
    	
    	//Peter发布了狩猎tiger的任务
    	hunterPeter.publish('tiger', 198)
    	
    	//猎人们发布(发布者)或订阅(观察者/订阅者)任务都是通过猎人工会(调度中心)关联起来的,他们没有直接的交流。
    

    观察者模式和发布订阅模式最大的区别就是发布订阅模式有个事件调度中心。

    观察者模式由具体目标调度,每个被订阅的目标里面都需要有对观察者的处理,这种处理方式比较直接粗暴,但是会造成代码的冗余。

    而发布订阅模式中统一由调度中心进行处理,订阅者和发布者互不干扰,消除了发布者和订阅者之间的依赖。这样一方面实现了解耦,还有就是可以实现更细粒度的一些控制。比如发布者发布了很多消息,但是不想所有的订阅者都接收到,就可以在调度中心做一些处理,类似于权限控制之类的。还可以做一些节流操作。

    观察者模式是不是发布订阅模式

    网上关于这个问题的回答,出现了两极分化,有认为发布订阅模式就是观察者模式的,也有认为观察者模式和发布订阅模式是真不一样的。

    其实我不知道发布订阅模式是不是观察者模式,就像我不知道辨别模式的关键是设计意图还是设计结构(理念),虽然《JavaScript设计模式与开发实践》一书中说了分辨模式的关键是意图而不是结构

    如果以结构来分辨模式,发布订阅模式相比观察者模式多了一个中间件订阅器,所以发布订阅模式是不同于观察者模式的;如果以意图来分辨模式,他们都是实现了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知,并自动更新,那么他们就是同一种模式,发布订阅模式是在观察者模式的基础上做的优化升级。

    不过,不管他们是不是同一个设计模式,他们的实现方式确实有差别,我们在使用的时候应该根据场景来判断选择哪个。

    展开全文
  • 1.设计模式之终极结合 ...我们最近几期博客打算主要讲一下单例模式、观察者模式、Build模式,目的是为了方便后期为大家带来RXJava+Retrofit2.0+Okhttp3结合使用的网络请求框架。 周末两天过的真快,不...

    1.设计模式之终极结合

    今天星期五了(异常的兴奋,周末又可以去**了,提前祝大家周末愉快),完成项目经理的需求之后开始继续最近几期博客的编写。承接上一篇博客单例模式,这一期我们一起来了解一下观察者模式。我们最近几期博客打算主要讲一下单例模式、观察者模式、Build模式,目的是为了方便后期为大家带来RXJava+Retrofit2.0+Okhttp3结合使用的网络请求框架。

    周末两天过的真快,不过我一直在想我怎么才能写的简单明了,写出观察者模式的精华。

    2.观察者模式定义

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

    3.观察者模式理解

    一个被观察者对象(ConcreteObservable也被叫为具体的主题ConcreteSubject)可以有一个或多个观察者(Observer)。观察者(这里说的就是具体观察者ConcreteObserver)可以是实现了 观察者(Observer) 接口的任意对象。一个 observable 实例改变后,调用 观察者(observable) 的notifyObservers()方法的应用程序会通过调用观察者的update() 方法来通知观察者该实例发生了改变。

    是不是感觉有点没理过来,很混乱。其实简单理解观察者模式就是:1个抽象的被观察者(java中的一个类Observable)和多个抽象的观察者(java中的一个接口Observer)两者之间的订阅——发布的关系;抽象的东西只是概念,所以我们要具体化,具体到我们的项目中的对象;就有了具体主题(ConcreteSubject 继承了观察者{Observable}类)和具体的观察者(ConcreteObserver实现了观察者{Observer}接口)。

    如果这样还是不好理解,我们就来个具体的例子,比如我们现在的微信公众号(把它认为是具体的主题继承了被观察者对象)以及很多微信用户(把它认为是具体的观察者实现 了观察者接口);我们用户只要订阅了某微信公众号,那么只要微信公众号发布信息,我们用户就会收到消息并调用更新方法(update())。这样一个关系叫观察者模式(更喜欢叫它为订阅——发布的模式)。

    4.UML类图

    观察者方法说明:

              只要改变了 observable 对象就调用此方法。

    被观察者方法说明:

              通知其所有观察者,内容发生变化。

              如果观察者与集合中已有的观察者不同,则向对象的观察者集中添加此观察者。

              从对象的观察者集合中删除某个观察者。

    角色介绍:

    • Subject(抽象主题):被观察者(Observable)的角色,抽象主题角色把所有观察者对象的引用都存入这个集合里,每个主题都可以有任意数量的观察者,抽象主题提供几个方法,可以增加和删除观察者对象以及通知观察者对象内容发生变化。
    • ConcreteSubject(具体主题):具体被观察者(ConcretObservable),该角色将有关状态存入具体观察者对象,在具体主题的内部状态发生改变时,给所有订阅过的观察者发出通知。
    • Observer(抽象观察者):观察者的抽象接口,该角色只有一个update()更新方法,当收到通知内容后更新自己的内容。
    • ConcreteObserver(具体观察者):该角色实现了抽象观察者接口,当收到主题的状态改变时更新自己的内容。

    5.JAVA API 

    • Observer(观察者接口Interface):

    •  Observable(被观察者) 

     

    6.观察者模式简单示例

    思前想后,我到底要做个什么例子啦,微信公众号——微信用户的(发布与订阅关系),确实比较贴近生活;但是好像这个例子有点烂大街了。我就做个项目经理(被观察者)——技术部员工(一群观察者,当然你说可不可只有一个技术人员了也可以的,全栈)这个例子吧;这个也挺好理解的吧,你被录用分配到技术部,不管你负责前端、后端、后台、数据库、还是美工;这样你们就要听项目经理的安排(订阅了),经理今天发布通知:必须在周5完成这个项目上线(发布)。是不是大家都受到消息开始干自己的事情,知道有一天前端干不下去了,离职了,是不是就解除这个订阅关系,不再受到通知。那么让我们一起来看代码: 

    • StaffObserver(具体观察者)
    import java.util.Observable;
    import java.util.Observer;
    
    /**
     * 员工观察者角色
     */
    public class StaffObserver implements Observer {
        private String staff;
        private String leader;
        LeaderSubject leaderSubject = new LeaderSubject("项目经理");
        public StaffObserver(String s) {
            staff = s;
        }
    
        @Override
        public void update(Observable observable, Object o) {
            System.out.println(staff+"接受到"+leader+"发送通知:"+o);
        }
    
        public void update(String str,Object o){
            leader = str;
            update(leaderSubject,o);
        }
    }
    
    • LeaderSubject(具体被观察者)
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Observable;
    
    /**
     * 领导主题角色继承被观察者
     */
    public class LeaderSubject extends Observable {
        private List<StaffObserver> mList;
        private String leader;
        public LeaderSubject(String s) {
            leader = s;
            this.mList = new ArrayList<StaffObserver>();
        }
        /**
         *
         * @param o 删除具体观察者
         */
        public synchronized void deleteObserver(StaffObserver o) {
            super.deleteObserver(o);
            if(mList != null && mList.size()>0){
                mList.remove(o);
            }
        }
    
        /**
         *
         * @param o 增加具体观察者
         */
        public synchronized void addObserver(StaffObserver o) {
            super.addObserver(o);
            if(mList !=null){
                mList.add(o);
            }
    
        }
    
        /**
         * 当调用setChanged(String msg)调用具体实现
         * @param msg
         */
        @Override
        public void notifyObservers(Object msg) {
            super.notifyObservers(msg);
            if(mList != null){
                for (StaffObserver s:mList) {
                    s.update(leader,msg);
                }
    
            }
        }
    
        /**
         * 被观察者内容发生改变
         * @param msg 改变的内容
         */
        public  void setChanged(String msg) {
            //消息更新,通知所有观察者
            notifyObservers(msg);
        }
    }
    
    • TestObserver(实现类)
    public class TestObserver {
        public static void main(String[] args) {
    
            LeaderSubject leaderSubject = new LeaderSubject("项目经理");
            StaffObserver frontEnd = new StaffObserver("FrontEnd");
            StaffObserver Database = new StaffObserver("Database");
            StaffObserver UI = new StaffObserver("UI");
    
    
            leaderSubject.addObserver(frontEnd);
            leaderSubject.addObserver(Database);
            leaderSubject.addObserver(UI);
            leaderSubject.setChanged("这周我们完成这个项目,并上线!");
    
            leaderSubject.deleteObserver(UI);
            System.out.println("------------------观察者减少");
            leaderSubject.setChanged("由于美工的离职,我们延迟上线!");
    
        }
    }
    
    • AS输出结果:

    • 记事本DOS命令输出结果: 

    是不是很简单,就1个具体观察者类和1个具体被观察这类,然后就是具体的实现类;员工的增加与减少不影响其他员工接受通知。在这个过程中整个流程都是依赖Observer和Observable这些抽象接口和类,所以StaffObserver和LeaderSubject完全没有耦合,保证了整个系统的灵活性和可拓展性。

    这就达到了我们解耦的效果了,观察者模式。

    7.观察者模式总结

    优点:

    观察者和被观察者没有耦合,增强了系统灵活性和可拓展性。

    缺点:

    被观察者是按顺序执行,如果业务负责,被观察者很多,那么就会影响效率;同时如果其中一个卡顿会影响后面的观察者,所以我们建议这种情况使用异步任务。

    8.更多请关注持续更新

    现在其实有很多观察者模式的具体实现:比如我们的Android源码BaseAdapter,开源框架EventBus,以及RxJava等等。

    如果想看的人多,我们会在这篇博客下继续更新EventBus和Rxjava的简单讲解以及源码分析。

    展开全文
  • 阿里P6+面试:介绍下观察者模式

    千次阅读 多人点赞 2021-06-03 00:03:19
    框架应用 观察者模式在框架的中的应用也是应该很多 第一种 熟悉JDK的人应该知道 在java.util 包下 除了常用的 集合 和map之外还有一个Observable类,他的实现方式其实就是观察者模式。里面也有添加、删除、通知等...
  • Java观察者模式(Observer)

    千次阅读 多人点赞 2019-02-16 23:57:11
      观察者模式java GOF23种设计模式中的一种。在最近介绍的Redis和ActiveMQ中都涉及到了观察者模式,所以我们在本文详细介绍下此模式: 观察者模式   观察者模式又称为发布/订阅(Publish/Subscribe)模式,在对象...
  • 设计模式 | 观察者模式及典型应用

    千次阅读 2018-10-24 01:05:45
    介绍观察者模式 微信公众号的发布/订阅示例 观察者模式总结 分析观察者模式的典型应用 JDK 提供的观察者接口中的观察者模式 Guava EventBus 中的观察者模式 JDK 委托事件模型DEM中的观察者模式 Spring ...
  • 面试官喜欢问的 设计模式之观察者模式

    万次阅读 多人点赞 2020-04-22 22:18:20
    这篇博客详细的介绍了JAVA设计模式之【观察者模式
  • 观察者模式(Observer Pattern)(有时又被称为模型(Model)-视图(View)模式、源-收听者(Listener)模式或从属者模式)是软件设计模式的一种。在此种模式中,一个目标物件管理所有相依于它的观察者物件,并且在它...
  • Java线程池及观察者模式解决多线程意外死亡重启问题,附件含两个要运行代码!
  • Android观察者模式

    千次阅读 2019-01-22 12:25:06
    定义 定义对象间一对多的关系,当一...Android内置了Observer和Observable,来看看观察者和被观察者的定义: 观察者 public interface Observer { void update(Observable var1, Object var2); } 被观察者 pub...
  • 观察者模式就是定义对象之间的一对多依赖,这样一来,当一个对象状态发生改变时,它的所有依赖者都会收到通知并自动更新。 这样的好处就是两个或多个对象之间松耦合,它们依然可以交互,但不太清楚彼此的细节。观察...
  • Android设计模式学习之观察者模式

    万次阅读 多人点赞 2017-02-17 00:25:00
    观察者模式在实际项目中使用的也是非常频繁的,它最常用的地方是GUI系统、订阅——发布系统等。因为这个模式的一个重要作用就是解耦,使得它们之间的依赖性更小,甚至做到毫无依赖。以GUI系统来说,应用的UI具有易变...
  • PHP 观察者模式 理解

    千次阅读 2018-11-29 23:39:12
    而我们为什么要用 “观察者模式”?这就需要从实际运用中来理解才能更好的运用!用如下的情境来说明吧。 事例,开始时我被安排做项目的登录,很快我就完成了。然后产品提出了另一个需求,用户登录后,给他们推送一...
  • 中介者模式与观察者模式

    千次阅读 2017-08-21 19:57:20
    中介者模式Mediator(中介者)模式是行为模式之一,在Mediator模式中,类之间的交互行为被统一放在Mediator的对象中,对象通过Mediator对象同其他对象交互,Mediator对象起着控制器的作用。  用一个中介对象来封装...
  • 设计模式(二)————观察者模式

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

    千次阅读 2019-09-19 21:44:10
    每个人应该都订阅了不少微信公众号,那你有没有注意到微信公众号的消息呢?你订阅的公众号号主每发布一篇文章,你都会主动的接收到文章的推送,并不需要你点开每个订阅的...每个公众号会有多名订阅,公众号跟订...
  • 设计模式不是解决业务逻辑问题, 而是为了解决开发管理的一种规范思路, 所以两年前我的例子是错误的, 如有读者建议直接去看一些视频老师的讲解, 此处留着警示自己! _______________________________________________...
  • 设计模式(五)观察者模式

    万次阅读 多人点赞 2016-03-02 17:41:50
    观察者模式(又被称为发布-订阅(Publish/Subscribe)模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听莫一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。
  • java观察者模式

    千次阅读 2018-09-04 10:53:37
    首先,弄明白两组概念:观察者(Observer)与被观察者(subject)、发布者(publicsher)与订阅者(subscriber)。这是相似的两组概念,讲的...观察者模式说白了,其实就是发布订阅模式,发布者发布信息,订阅者获...
  • 文章目录1. 定义2. 设计3. 应用3.1. 事件监听3.2. 事件总线3.3. 消息队列3.4. Reactive4. 特点4.1....观察者模式(Observer Pattern):定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生...
  • C++实现观察者模式

    千次阅读 2018-08-07 10:46:47
    【有时又被称为模型-视图(View)模式、源-收听者(Listener)模式或为发布-订阅模式(目标就是通知的发布者,观察者是通知的订阅者(接受通知))。】  Observer 的一个实例 Model/View/Control(...
  • 观察者模式简单实现

    千次阅读 2019-02-25 16:19:05
    观察者模式:观察者(Observer)关心被观察者(Subject)的某个状态(subjectState),一旦状态变化,观察者就能收到通知(Notify),并更新自己的状态(observerState)。 动机:在软件构建 过程中,我们需要为...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 298,927
精华内容 119,570
关键字:

观察者模式