发布-订阅(观察者)模式演变

(一)什么是观察者模式

发布-订阅,这两个词语是对观察者的最好解释,现实生活中,这样的案例有很多,比如在篮球比赛过程中教练,喊一个暂停,然后球员和裁判都做相关的响应,还有比如OA里面发布的放假通知等等。无论是篮球比赛,还是OA的通知,都存在一个角色,它的作用就是保持对相关问题的关注,在问题发生变化的时候,是Ta把消息通知给相关各方。观察者模式也差不多这样,它抽象一类对象(观察者)专门负责"盯着"目标对象,当目标对象状态有变动的时候,每个观察者就会获得通知并迅速做出响应,观察者模式解决的也是调用通知关系所带来的依赖。

(二)观察者模式的演变

下面请看代码。有三个类,A,B,C想接收来自X的消息,简单的说X发生变化,他们也跟着变化。

public class A {
        public int Data;
        public void Update(int data) {
            this.Data = data;
        }
    }

    public class B {
        public int Count;
        public void NotifyCount(int data) {
            this.Count = data;
        }
    }

    public class C {
        public int N;
        public void Set(int data) {
            this.N = data;
        }
    }

    //上面这三个类,类A,B,C是希望获得X通知的类型
    public class X {
        private int data;
        public A InstanceA;
        public B InstanceB;
        public C InstanceC;
        public void SetData(int data) {
            this.data = data;
            InstanceA.Update(data);
            InstanceB.NotifyCount(data);
            InstanceC.Set(data);
        }
    }   在我们调用的时候,应该这么做
A a = new A();
            B b = new B();
            C c = new C();
            X x = new X();
            x.InstanceA = a;
            x.InstanceB = b;
            x.InstanceC = c;
            x.SetData(10);
            Console.WriteLine("x发出消息了");
            Console.WriteLine(a.Data);
            Console.WriteLine(b.Count);
            Console.WriteLine(c.N);
对于上面这种做法,大家应该都会。下面是这个上面例子的类图关系,从这里,我们可以看得X和太多类直接关联了。已经很不符合面向对象的设计原则了。

经过观察,我们发现类A,B,C都有个共同之处,都是有一个类似于更新的方法,如果对他们进行抽象的话呢,就可以让类X仅仅依赖于一个抽象的类型。下面直接看代码

  public interface IUpdatableObject {
        int Data {get;}
        void Update(int newData);
    }

    public class A : IUpdatableObject {

        private int data;
        public int Data { get { return this.data; } }

        public void Update(int newData) {
            this.data = newData;
        }
    }

    public class B : IUpdatableObject {

        private int data;
        public int Data { get { return this.data; } }

        public void Update(int newData) {
            this.data = newData;
        }
    }

    public class C : IUpdatableObject {

        private int data;
        public int Data { get { return this.data; } }

        public void Update(int newData) {
            this.data = newData;
        }
    }

    public class X {
        private IUpdatableObject[] objects = new IUpdatableObject[3];

        //这个是索引器的用法
        public IUpdatableObject this[int index] { set { objects[index] = value; } }

        private int data;
        public void Update(int newData) {
            this.data = newData;
            foreach(IUpdatableObject obj in objects) {
                obj.Update(newData);
            }
        }
    }

//调用代码如下
    X x = new X();
            IUpdatableObject a = new A();
            IUpdatableObject b = new B();
            IUpdatableObject c = new C();
            x[0] = a;
            x[1] = b;
            x[2] = c;
            x.Update(10);
            Console.WriteLine("x发出了消息");
            Console.Write(a.Data);
            Console.Write(b.Data);
            Console.Write(c.Data);

通过上面我们就可以依赖于抽象了,比如当我们要新增加一个订阅者的时候,也不用去类X里面改内部代码,请看类图。

下面开始我们的版本的三;

先看看这幅图,以后我们把消息的发布者,叫做主题,接收着叫做观察者。主题类似于前文的X类,观察者类似于A,B,C类。

第二版本的时候,我们已经解决了两个对象之间的松耦合,关于观察者的一切,主题只需要知道他实现了哪个接口(前文中的IUpdatableObject接口),只要是实现了这个接口的,主题就会把他认为是观察者。

继续这观察者模式的发展和演变,到了我们第三个版本的观察者模式。到了这步,我们想到如果有观察者要退出,不订阅这个主题了,等等操作(当主题发生变化的时候,,我们应该怎么做)。根据我们的面向对象的经验,我们应该很容易想到应该把主题对象也要抽象化。

public interface ISubject {

        int Data { get; set; } //这个Data就是类似于用来发送消息的。

        /// <summary>
        /// 追加
        /// </summary>
        /// <param name="obs"></param>
        void Attach(IObserver obs);

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="obs"></param>
        void Detach(IObserver obs);
        /// <summary>
        /// 监听
        /// </summary>
        void Notify();
    }

    public interface IObserver {
        int Data { get; set; }
        void Update(int n);
    }

    public class ConcreteSubjectA : ISubject {
        public int Data { get; set; }

        public List<IObserver> ObsList = new List<IObserver>();
        public void Attach(IObserver obs) {
            Console.WriteLine("添加观察者成功");
            ObsList.Add(obs);
        }

        public void Detach(IObserver obs) {
            Console.WriteLine("删除观察者成功");
            ObsList.Remove(obs);
        }

        public void Notify() {
            foreach(var obs in ObsList) {
                obs.Update(this.Data);
            }
        }
    }
    public class ConcreteObserverA : IObserver {

        public int Data { get; set; }
        public void Update(int n) {
            this.Data = n;
        }
    }

    public class ConcreteObserverB : IObserver {
        public  int Data { get; set; }
        public void Update(int n) {
            this.Data = n;
        }
    }

    public class ConcreteObserverC : IObserver {
        public int Data { get; set; }
        public void Update(int n) {
            this.Data = n;
        }
    }
 ISubject csA = new ConcreteSubjectA();
            IObserver a = new ConcreteObserverA();
            IObserver b = new ConcreteObserverB();
            IObserver c = new ConcreteObserverC();
            csA.Attach(a);
            csA.Attach(b);
            csA.Attach(c);
            csA.Data = 20;
            //移除观察者
            csA.Detach(b);
            csA.Notify();
            //我们现在做的这个版本相对于上一个版本就是增加了对观察者的管理。
            //以及我们可以让我们的程序都是依赖于抽象。

            Console.WriteLine($"类A的数据为:{a.Data}");
            Console.WriteLine($"类B的数据为{b.Data}");
            Console.WriteLine($"类C的数据为{c.Data}");
降到这里基本上把观察者模式给讲完了,我更加喜欢叫做发布订阅模式,这样更加好理解。

我们上面的那个例子还可以在抽象一点,利用泛型类和泛型方法来做,真正的达到抽象。下面是最终版本的实现代码(把泛型类和泛型方法用上),这个大家可以思考下怎么做?相关代码暂时不贴出来先。

最后,希望大家能够带带我这个菜鸟,谢谢各位。

时间: 2024-08-04 15:32:11

发布-订阅(观察者)模式演变的相关文章

学习javascript设计模式之发布-订阅(观察者)模式

1.发布-订阅模式又叫观察者模式,它定义对象之间一种一对多的依赖关系. 2.如何实现发布-订阅模式 2-1.首先指定好发布者 2-2.给发布者添加一个缓冲列表,用户存放回调函数以便通知订阅者 2-3.最后发布消息时候,发布者会遍历这个缓存列表,依次触发里面存放的订阅者回调函数 例子: var salesOffice = {};salesOffice.clientList = [];salesOffice.listen = function(key,fn){    if(!this.clientL

设计模式 - 发布-订阅者模式

1.发布-订阅者 设计模式 定义 定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知 观察者模式和发布订阅模式区别 观察者模式是由具体目标(发布者/被观察者)调度的,而发布/订阅模式是由独立的调度中心进行调度,所以观察者模式的订阅者与发布者之间是存在依赖的,而发布/订阅模式则不会:可以说发布订阅模式是观察者模式进一步解耦,在实际中被大量运用的一种模式 ** 观察者模式 ** 1.定义/解析 目标和观察者是基类,目标提供维护观察者的一系列方法,观察者提供更

Vue发布-订阅者模式

1.vue响应原理: vue.js采用数据劫持结合发布-订阅者模式,通过Object.defineProperty()来劫持data中各个属性的setter.getter,在数据变动时,发布消息给订阅者,触发响应的监听回调. (setter和getter是对象的存储器属性,是一个函数,用来获取和设置值) 2.发布-订阅者模式的作用: 处理一对多的场景,应用于不同情况下的不同函数调用 优点:低耦合性,易于代码维护: 缺点:若订阅的消息未发生,需消耗一定的时间和内存. <!DOCTYPE html>

ActiveMQ发布-订阅消息模式

一.订阅杂志我们很多人都订过杂志,其过程很简单.只要告诉邮局我们所要订的杂志名.投递的地址,付了钱就OK.出版社定期会将出版的杂志交给邮局,邮局会根据订阅的列表,将杂志送达消费者手中.这样我们就可以看到每一期精彩的杂志了. 仔细思考一下订杂志的过程,我们会发现这样几个特点:1.消费者订杂志不需要直接找出版社:2.出版社只需要把杂志交给邮局:3.邮局将杂志送达消费者.邮局在整个过程中扮演了非常重要的中转作用,在出版社和消费者相互不需要知道对方的情况下,邮局完成了杂志的投递. 二. 发布-订阅消息模

JS 设计模式八 -- 发布订阅者模式

概念 发布---订阅模式又叫观察者模式,它定义了对象间的一种一对多(一个发布,多个观察)的关系,让多个观察者对象同时监听某一个主题对象,当一个对象发生改变时,所有依赖于它的对象都将得到通知. 优点 1.支持简单的广播通信,当对象状态发生改变时,会自动通知已经订阅过的对象. 2.发布者与订阅者耦合性降低 缺点 创建订阅者需要消耗一定的时间和内存. 如果过度使用的话,反而使代码不好理解及代码不好维护. 代码实现 var Event = (function(){ var list = {}, // 缓

ActiveMQ的(点对点&amp;发布/订阅通信模式)和(持久化方式)

ActiveMQ的持久化 消息持久性对于可靠消息传递来说应该是一种比较好的方法,有了消息持久化,即使发送者和接受者不是同时在线或者消息中心在发送者发送消息后宕机了,在消息中心重新启动后仍然可以将消息发送出去,如果把这种持久化和ReliableMessaging结合起来应该是很好的保证了消息的可靠传送. 消息持久性的原理很简单,就是在发送者将消息发送出去后,消息中心首先将消息存储到本地数据文件.内存数据库或者远程数据库等,然后试图将消息发送给接收者,发送成功则将消息从存储中删除,失败则继续尝试.消

CRM中间件里的发布-订阅者模式

从事务码SMW01里能观察到一个BDOC可能被发送往不止一个目的site去,比如下图所示的5个site都会收到该site,而高亮显示的SMOF_ERPSITE代表ERP系统QI3的client 504会接收到这个BDOC. 所以上图列表里的site是从哪里读取出来的? 以BDOCPRODUCT_MAT为例,在视图SMW3FDBDOC里维护回调函数: 第一个回调SMOH_REPLICATION_WRAPPER_MSG负责决定需要从CRM将该BDOC发送到哪些site去. 这个回调是自动生成的: 在

javascript发布订阅pubsub模式

首先使用数组缓存订阅者订阅的消息,当订阅者订阅消息的时候,把订阅的消息push到指定消息的队列中,当发布者发布消息的时候,我们遍历执行push到指定消息队列中的回调事件. var Pubsub=(function(){ var eventObj={}; return { subscribe:function(event,fn){ eventObj[event]=fn }, publish:function(event){ if(eventObj[event]) eventObj[event]()

经典的发布订阅者模式

function Pubsub() { this.handlers = {};}Pubsub.prototype = { on: function (eventType, handler) { var self = this; if (!(eventType in self.handlers)) { self.handlers[eventType] = []; } self.handlers[eventType].push(handler) }, emit: function (eventTyp

JavaScript实现的发布/订阅(Pub/Sub)模式

JavaScript实现的发布/订阅(Pub/Sub)模式时间 2016-05-02 18:47:58  GiantMing's blog原文  http://giantming.net/javascriptshi-xian-de-fa-bu-ding-yue-pub-sub-mo-shi/主题 JavaScript 观察者模式前段时间看了一下发布订阅者模式(也叫观察者模式),今天看<基于mvc的JavaScript的富应用开发>又看到了它,这个设计模式是非常有用的,正好写篇博客来分享一下.(