在淘宝,我们对某类产品感兴趣,就会订阅该产品信息,当有货到后,我们会收到提示信息。
下面就简单用Dojo订阅/发布模式来说明其实现的基本原理。
大概功能需求:
买家先在产品中心注册,说自己对衣服等感兴趣,接着产品中心发布了一条新信息“衣服到新款了,亲快来采购吧”,这时买家将立即收到这条消息,并显示出来(在本例中就是在firefox浏览器的firebug模拟控制台输出这条新信息)。然后买家可能对别的信息感兴趣,再次订阅,等等重复上述过程。最后买家不打算再订阅衣服信息了,就在产品中心取消了对衣服信息的注册。大概流程就是这样子的。
果断上代码看效果,然后再来分析!
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="DojoSubPub.aspx.cs" Inherits="DojoTest.DojoSubPub" %> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title></title> <%-- 引入 Dojo--%> <script src="http://ajax.googleapis.com/ajax/libs/dojo/1.7.2/dojo/dojo.js" type="text/javascript"></script> <script type="text/javascript"> //定义一个产品主题列表 var NewsReporter = { clothes: function (message) { for (var i = 0; i < message.length; i++) { console.info("淘宝掌柜订阅提醒:" + message[i]); } }, shoes: function (message) { for (var i = 0; i < message.length; i++) { console.info("淘宝掌柜订阅提醒:" + message[i]); } }, mixed: function (clothes, shoes) { console.info("混合订阅提醒"); this.clothes(clothes); this.shoes(shoes); } } //订阅衣服信息 handle1 = dojo.subscribe("clothes news", NewsReporter, "clothes"); //订阅鞋子信息 handle2 = dojo.subscribe("shoes news", NewsReporter, "shoes"); //订阅衣服和鞋子信息 dojo.subscribe("mixed news", NewsReporter, "mixed"); //发布信息 dojo.publish("clothes news", [["衣服到新款了,亲快来采购吧!"]]) dojo.publish("shoes news", [["鞋子到新款了,亲快来采购吧!"]]); dojo.publish("mixed news", [["衣服到新款了,快来采购吧!"], ["鞋子到新款了,快来采购吧!"]]); //取消订阅 dojo.unsubscribe(handle1); dojo.unsubscribe(handle2); //发布信息 dojo.publish("clothes news", [["衣服到新款了,亲快来采购吧!"]]) dojo.publish("shoes news", [["鞋子到新款了,亲快来采购吧!"]]); dojo.publish("mixed news", [["衣服到新款了,快来采购吧!"], ["鞋子到新款了,快来采购吧!"]]); </script> </head> <body> </body> </html>
在控制台输出结果如下:
订阅 / 发布模式实现是比较简单的。 dojo 维护了一个主题列表,用户订阅某一主题时,即把此主题及其处理函数添加到主题列表中。当有此类主题发布时,跟这一主题相关的处理函数会被顺序调用。
我们上面的代码就是说明其是如何工作的。
在 Dojo 中,跟主题订阅 / 发布有关的函数有三个:
dojo.subscribe = function(topic,context,method)
subscribe 函数用来订阅某一主题;参数 topic 表示主题名字,是一个字符串; context 是接收到主题后调用的事件处理函数所在的对象,function 是事件处理函数名。
dojo.unsubscribe = function(handle)
取消对于某一主题的订阅;参数 handle 是 dojo.subscribe 返回的句柄
dojo.publish = function(topic, args)
发布某一主题;参数 topic 是主题的名字,args 表示要传递给主题处理函数的参数,它是一个数组,可以通过它传递多个参数给事件处理函数。
注意点:
1、如果用户使用了相同的处理函数重复订阅某一主题两次,在主题列表中这是不同的两项,只是他们都对同一主题感兴趣。当此类主题发布时,这两个处理函数都会被调用,而不会出现第二个处理函数覆盖第一个处理函数的状况。
2、先订阅,再发布。主题发布的时候,订阅了这一主题的事件处理函数会被立即调用。
3、发布函数的参数为数组,发布第一条消息时使用的是[["衣服到新款了,亲快来采购吧!"]],这是一个二维数组,因为事件处理函数 NewsReporter.clothes,NewsReporter.shoes,以及 NewsReporter.mixed 的参数已经是一个数组,所以在发布时必须把消息事件这个数组再放在另一个数组中才能传递给这些事件处理函数。而“ mixed ”消息的处理函数有两个参数,所以发布“ mixed ”的消息时,参数为:
[["衣服到新款了,快来采购吧!"], ["鞋子到新款了,快来采购吧!"]]
二维数组中的第一个数组表示衣服,第二个数组表示鞋子。
4、取消订阅时,必须把所有的订阅都取消。重复的订阅行为返回的句柄是不一样的,在本例中 handle1 和 handle2 是不同的,必须都注销。只有在 handle1 和 handle2 都被注销后,产品中心发布的消息才不会被这个买家接收到。
总结:
如果你对设计模式有所了解,会发现Dojo“订阅/发布”与《观察者模式》非常相似。
Dojo 提供的“订阅/发布”模式可以看作是一个预订系统,使得事件源和事件处理函数并不直接关联,用户先预定自己感兴趣的主题,当此类主题发布时,将在第一时间得到通知。在订阅/发布模式下,预订的时候并不确定此类主题是否已存在,以后是否会发布。只是在主题发布之后,会立即得到通知。订阅/发布模式是靠主题把事件和事件处理函数联系起来的。