美高梅网址注册-澳门mgm4858集团登录网址
做最好的网站
来自 澳门mgm4858集团登录网址 2019-10-06 06:02 的文章
当前位置: 美高梅网址注册 > 澳门mgm4858集团登录网址 > 正文

其中使用订阅者和发布者实现消息队列的方式,

在事件驱动的环境中,比如浏览器这种持续寻求用户关注的环境中,观察者模式是一种管理人与其任务(确切的讲,是对象及其行为和状态之间的关系)之间的关系的得力工具。用javascript的话来讲,这种模式的实质就是你可以对程序中某个对象的状态进行观察,并且在其发生变化时可以得到通知。

一、观察者模式

C#和Java这两大流行的编程语言,相似程度极高。本文就来欣赏一下C#委托和Java回调的异曲同工之妙。

设计模式中有一个非常著名的“观察者模式”,又称为“发布-订阅模式”。大概意思是一方发布消息,另一方订阅消息。订阅消息的一方不必等待消息的到来,而是径自干自己的事情去。如果发布消息的一方发布了新的消息,就会自动通知订阅者接收。

其实不必在意这种设计模式叫什么,事实上所谓的“观察者模式”的代码经常出现在我们编写的程序中,而直到计划写这篇文章时我才知道原来这就是大名鼎鼎的“观察者模式”。所以说编程的套路都是人们经验的结晶,之后不过再套上个炫酷的名字而已。

言归正传,下面我们分别用C#和Java设计出发布-订阅的效果。

订阅者和发布者模式,通常用于消息队列中。一般有两种形式来实现消息队列,一是使用生产者和消费者来实现,二是使用订阅-发布者来实现。其中使用订阅者和发布者实现消息队列的方式,就会用订阅者模式。

观察者模式中存在俩个角色:观察者和被观察者。也可以叫做发布者和订阅者。这种模式在javascript中有几种不同的实现方法,下面将对其中的一些实现方式进行考察。

二、订阅者部分

通常订阅者都是用户,对于用户来说,打算订阅一种消息,最简单又合理的做法应该是:

  1. 告诉发布者我要订阅哪一条消息;
  2. 把我的消息处理方法提交给发布者。

这就好比订阅一份报纸时,先告诉报社我要订哪一种报纸,再告诉报社我家邮筒的地址。

让我们先用C#试试如何实现:

namespace PublisherSubscriberDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            Publisher publisher = new Publisher();
            publisher.SomeMessage += message => { Console.WriteLine("Subscriber 1: " + message); };
            publisher.SomeMessage += message => { Console.WriteLine("Subscriber 2: " + message); };
            publisher.Start();
        }
    }
}

为了使代码简洁,我们利用C#的lambda表达式把上面提到的两步工作写到了一行中(否则就要单独定义消息处理函数)。这行代码的效果是,把等号右侧的lambda表达式所代表的消息处理方法添加到发布者的SomeMessage消息的订阅列表中。发布者的订阅列表SomeMessage是一个委托(delegate),它可以添加所有订阅者的消息处理方法。这里我们让订阅者订阅了两次该消息,以代表多个订阅者的情况。

如果用Java实现大概是这个样子:

public class PublisherSubscriberDemo {
    public static void main(String[] args) {
        Publisher publisher = new Publisher();
        publisher.addOnMessageArriveListener(message -> { System.out.println("Subscriber 1:" + message); });
        publisher.addOnMessageArriveListener(message -> { System.out.println("Subscriber 2:" + message); });
        publisher.start();
    }
}

代码量基本与C#相同。这里使用了Java 8的lambda表达式使代码更简洁(否则就要用到匿名内部类)。由于Java中没有委托,所以只能用发布者提供的addOnMessageArriveListener把消息处理方法传递进去。

所谓的订阅者,就像我们在日常生活中,订阅报纸一样。我们订阅报纸的时候,通常都得需要在报社或者一些中介机构进行注册。当有新版的报纸发刊的时候,邮递员就需要向订阅该报纸的人,依次发放报纸。因此代码实现该模式,通常需要两个步骤:

模式的实践:

三、发布者部分

对于发布者来说,需要做的工作也有两条:

  1. 接收订阅者的消息处理方法;
  2. 在适当的时候调用这些方法。

其效果就相当于订阅者的消息处理方法在消息抵达的时候自动执行了,而实质上则是发布者手动调用了这些方法。

先来看C#的代码实现:

namespace PublisherSubscriberDemo
{
    class Publisher
    {
        public delegate void Message(string message);
        public Message SomeMessage;

        public void Start()
        {
            while (true)
            {
                SomeMessage("Some message from publisher.");
                System.Threading.Thread.Sleep(1000);
            }

        }
    }
}

是不是感觉很清爽?C#在编码效率上做的非常贴心,这里用的委托,可以接收任意数量的消息处理方法,只要这些方法和Message的参数及返回值相同。并且在调用SomeMessage时只需要写一次,就可以调用所有订阅者的消息处理方法。

相比之下,Java的代码就显得臃肿一些:

public class Publisher {

    private List<MessageArriveListener> listeners = new ArrayList<MessageArriveListener>();

    public interface MessageArriveListener {
        void MessageArrived(String message);
    }

    public void addOnMessageArriveListener(MessageArriveListener listener) {
        listeners.add(listener);
    }

    public void start()
    {
        while (true) {
            for (MessageArriveListener listener : listeners) {
                listener.MessageArrived("Some message from publisher.");
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

}

我们需要手动设计一个List来保存所有的消息处理方法(在Java中通常称为监听器),然后在适当的时候遍历这个列表一一通知订阅者。当然,Java的优点是代码语法简单,容易理解。比如所谓的监听器就是一个自定义接口,订阅者传进来的消息处理方法必须是一个实现该接口的类(通常是匿名内部类或lambda表达式)。

1、初始化发布者、订阅者。2、订阅者需要注册到发布者,发布者发布消息时,依次向订阅者发布消息。

在javascript中有多种方法可以实现发布者-订阅者模式,在展示这些示例之前,我们先确保各种角色的扮演者(对象)及其行为(方法)都已经就绪。

四、运行结果

C#代码和Java代码的运行效果完全一致,都是每秒钟打印两句话。

图片 1

C#结果

图片 2

Java结果

演示代码已上传GitHub仓库:
C#:https://github.com/jingedawang/PublisherSubscriberDemo-CSharp
Java:https://github.com/jingedawang/PublisherSubscriberDemo-Java

  • ##### 订阅者注册
  • 订阅者可以订阅和退订。他们还要接收。他们可以在“由人投送”和“自己收取”之间进行选择。
  • 发布者负责投送。他们可以在“送出”和“由人取”之间进行选择。

五、参考资料

c# event关键字的意义 lulu_jiang
Java Lambda表达式入门 Constantin Marian Alin

图片 3订阅者注册.png

下面是一个发布者和订阅者之间的互动过程的高层示例。

  • ##### 发布者发布消息
var Publisher = new Observable;
var Subscriber = function (news) {
    //news delivered directly to my proch;
}
Publisher.subscribeCustomer(Subscriber);
Publisher.deliver('extre,extre,read all about it!');
Publisher.unSubscribeCustomer(Subscriber);

图片 4发布者发布消息.png

在这个模型中可以看出,发布者处于明显的主导。他们负责登记其客户,而且有权停止投送。最后新的报纸出版后它们会将其投送给客户。

代码实现如下(一个常见的例子,双十一商品打折,只有关注该商品的客户才能收到该商品打折的信息):商品信息类主要有成员变量来存放所有关注该商品的顾客(ArrayList),同时存在发布消息的方法,客户关注商品的方法(即向客户容器中添加客户)等。

上面的代码创建了一个新的可观察对象(Observable)。它有三个实例方法:subscribeCustomer、unSubscribeCustomer和 deliver。subscribeCustomer方法以一个订阅者的回调函数为参数。deliver方法在调用过程中将通过这些回调函数把数据发送给每一个订阅者。

//商品类class Product{ private ArrayList<Client> clientArrayList = new ArrayList<Client>(); public void notify(String info){ //对于所有关注该商品的顾客进行遍历,依次将信息发布出去 for(Client client:clientArrayList){ client.receiveInfo; } } public void register(Client client){ clientArrayList.add; }}

下面的例子处理同一类问题,但是发布者和订阅者之间的互动方式有所不同。

客户类,即订阅者,用来接受商品发布的打折信息:

var newYorkTime = new Publisher;
var AustinHerald = new Publisher;
var SfChronicle = new Publisher;


var Jon = function (from) {
    console.log('Delivery from'+from+'to jon');
}
var Lindsay = function (from) {
    console.log('Delivery from'+from+'to Lindsay');
}
var Quadaras = function (from) {
    console.log('Delivery from'+from+'to Quadaras');
}

jon.
    subscribe(newYorkTime).
    subscribe(SfChronicle);

Lindsay.
    subscribe(newYorkTime).
    subscribe(AustinHerald).
    subscribe(SfChronicle);

Lindsay.
    subscribe(newYorkTime).
    subscribe(SfChronicle);

newYorkTime.deliver('Here is your paper!');
AustinHerald.deliver('News').deliver('REviews').deliver('Coupons');
SfChronicle.deliver('the weather is sill chilly').deliver('hello..');
class ConcreteClient { private String name; public ConcreteClient(String name){ this.name = name; } //用来接受发布者发布的消息 public void receiveInfo(String info) { System.out.println(this.name + ":收到信息(" + info + ")"); }}

在这个例子中,发布者的创建方式和订阅者接收数据的方式没有多少改变,但是用于订阅和退订权的一方变成了订阅者,当然,负责发送数据的还是发布者一方。

测试:

本类中的发布者是 Publisher 的实例。他有一个deliver方法。而作为订阅者的函数对象则拥有subscribe和unsubscribe俩个方法。订阅者只是普通的回调函数,这俩个方法是通过扩展Function的prototype而加入的,下面我们将一步一步的构建符合需要的API。

@Testpublic void test(){ Product product = new Product(); //a 用户关注商品 product.register(new ConcreteClient; //b 用户关注商品 product.register(new ConcreteClient; //c 用户关注商品 product.register(new ConcreteClient; //d 用户关注商品 product.register(new ConcreteClient; product.notify("商品编号为D1403121717大减价"); }

构建观察者API:

运行结果:

function Publisher(){
    this.subscribe = [];
}

本文由美高梅网址注册发布于澳门mgm4858集团登录网址,转载请注明出处:其中使用订阅者和发布者实现消息队列的方式,

关键词: