《dojo 边学边用》(04),发布/预订通信 ,dojo内置的观察者模式(dojo.publish 和 dojo.subscribe )
dojo.publish 和 dojo.subscribe
//dojo.publish 和 dojo.subscribe :dojo实现的简便强大的观察者模式
发布/预订通信
虽然dojo.connect提供的直接”连接式“通信能够解决不少问题,但在需要多个部件匿名通信情况下,则更适合使用间接的”广播式“通信。
在这些情况下,可以使用dojo.publish 和 dojo.subscribe 。
一个经典的例子就是按照一对多的关系实现一个JavaScript对象与其他对象之间的通信。此时,与建立并管理多个具有高内聚性的dojo.connect连接相比,更简单方案应该是让一个部件在事件发生时发布通知(同事也可以传递数据),而让其他部件能够预订该通知并在事件发生时自动执行相应操作。这种方式的好处在于负责广播的对象不需要知道什么对象预订了通知,甚至无需知道其他对象是否存在,【设计模式中典型的观察者模式】
发布/预订通信的API。(调用dojo.subscribe方法时可以省略context参数。该方法在内部能够按照我们的意愿处理参数“与dojo.connect方法一样”)
//事件发布
dojo.publish(/*String*/ topic , /*Array*/ args )
//topic发布的事件主题,args发布的事件参数
//事件订阅
dojo.subscribe(/*String*/ topic ,
/*Object | null*/ context ,
/*String | Function*/ method )//返回一个句柄对象
//topic要订阅的事件主题,
//退订,取消订阅
dojo.unsubscribe(/*Handle*/ handle)
//handle 就是要退订的事件的句柄
//【说明:和dojo.connect对象返回的句柄对象一样,dojo.subscribe返回的句柄对象也可以看成是一个黑盒子,仅在退订的时候才有用】
下面是一个使用dojo.publish和dojo.subscribe的示例:
function Tom(topic) {
this.topic = topic;
this.hello = function () {
alert("Hello,I'm Tom!");
//Tom直接发布信息,不针对某个具体的目标
dojo.publish(this.topic);
}
}
function Jerry(topic) {
this.topic = topic;
this.hello = function () {
alert("Hello,I'm Jerry");
}
//Jerry直接预订信息,但不针对某个具体的来源
dojo.subscribe(this.topic, this, "hello");
}
var tom = new Tom("/hello");
var jerry = new Jerry("/hello");
tom.hello();
第一个方法tom先是publish 发布了主题,第二个方法Jerry又subscribe订阅了方法.
【大家应该注意到倒数第2,第3行,事件主题是个字符串,并且字符串的开头是一个正斜杠。这是dojo的推荐写法,约定在主题名称前添加一个正斜杠,由于在JavaScript中,代码中正斜杠不常用,因此可以很容易的识别主题名称】
dojo.connect只能在特定的来源于特定的目标之间建立连接,而发布/订阅通信由于采用广播方式,因此对发送通知(或者是发布主题的事件)的来源和接收通知(或者注册订阅事件)的目标没有任何限制。松散耦合的架构之所以强大,原因就在于他能以最低的投入和最简单的设计,使应用程序可以在概念上被理解为一种相关插件的集合。
另外,也可以为publish提供第二个参数,该参数必须是一个数组,【array】,这个数组最终将被subscribe处理程序以单个命名参数的形式来接收!
[【一个常见的错误,就是忘记传递给dojo.publish数据必须要放入数组中,而dojo.subscribe的处理程序是以单个参数的形式来接收这些参数】]
下面稍加修改,示范一下dojo.unsubscribe的取消订阅。
<!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>
<script type="text/javascript" src="js/dojo/dojo.js"></script>
<script type="text/javascript">
function Tom(topic) {
this.topic = topic;
this.hello = function () {
alert("Hello,I'm Tom!");
//Tom直接发布信息,不针对某个具体的目标
dojo.publish(this.topic);
}
}
function Jerry(topic) {
this.topic = topic;
this.hello = function () {
alert("Hello,I'm Jerry");
//取消订阅,handle
dojo.unsubscribe(this.handle);
}
//dojo.subscribe返回一个句柄handle
this.handle = dojo.subscribe(this.topic, this, "hello");
}
var tom = new Tom("/hello");
var jerry = new Jerry("/hello");
</script>
</head>
<body>
<button onclick="tom.hello();">click me</button>
</body>
</html>
第一次点击按钮的时候,会弹出tom的"Hello,I'm Tom!",和jerry的"Hello,I'm Jerry",
然后再点击按钮,由于取消了订阅,将只会弹出tom的"Hello,I'm Tom!",而jerry不会再对/hello这个主题作回应了,因为他已经取消对这个主题的订阅了。
dojo.connectPublisher
最后还有一种可能的情况,假设你不确定是否可以修改Tom的hello方法,以便在其中包括对dojo.publish的调用,也许是因为存在禁止这样做的外部限制,或者那些代码一开始不是你编写的,不过,无论怎么样也无需担心,此时可以使用另外一个方法,就是 dojo.connectPublisher ,让它在特定时间发生时负责向我们发布通知:
function Tom() {
this.hello = function () {
alert("Hello,I'm Tom!");
}
}
function Jerry() {
this.greet = function () {
alert("Hello,I'm Jerry");
}
}
var tom = new Tom();
var jerry = new Jerry();
var topic = "/SayHi";
dojo.subscribe(topic, jerry, "greet");
dojo.connectPublisher(topic, tom, "hello");
tom.hello();
【注意:事实上,connectPublisher的后台工作原理就是每当特定的函数被调用时,就通过dojo.connect在该函数调用与dojo.publish调用之间建立一个连接】
上一篇和这一篇的学习,小结一下,我们应该能够达到如下的学习目标:
小结:
1,理解dojo.connect能够标准化传入时间处理程序中的事件对象,因而提供了跨平台的移植能力。
2,理解如何使用dojo.connect连接任意DOM时间,JavaScript对象事件和普通函数,从而创建事件驱动的响应模式、
3,使用发布/预订通知建立连接并在应用程序中实现松散耦合的通信架构。
4,知道在应用程序架构设计中使用dojo.connect 与 发布 dojo.publish/预订 dojo.subscribe 通信的利弊得失。
通过学习,我觉得dojo还是很不错的,虽然之前一直用jquery,对jquer熟悉和了解,但是dojo的面向对象更强大、