一直以来对观察者模式(Observer)一直理解为订阅发布模式,这样或许更好理解一些。现实中的博客RSS定制(在谷歌pubsubhubbub未出现以前,客户端都是被动的拉数据,PULL模式),需要客户端主动定时轮询方可。谷歌PUBSUBHUBBUB协议的问世,是一个创新,RSS主动推送的协议,非常实时,发布-订阅的最好典型。
观察者模式的详细定义以及相关理论,可以参见《设计模式》,里面讲的很透彻。
本文将带来一个在线版本的订阅-发布,用户添加一篇博文,所有订阅者可以马上得到通知,主动推送方式,避免了系统的大量无谓请求。虽有点PUBSUBHUBBUB协议的味道,但离实践还缺少很多,是一个演示。
这个演示模拟的场景是关心特定博主的所有订阅者可以在新的博文发表之后的瞬间得到通知。从博文的发布到通知所有的订阅者知晓,可以以毫秒计算(比较理想的情况下,诸如服务器性能强劲,网络好,算法不错等)。但这里的订阅者是有限制的,必须要有一个可以被内容发布者服务器回调的URL地址,否则将不能实时通知到订阅者。这里强调的是可以被内容发布者服务器访问。演示模拟的场景在一个机器上多个站点之间进行,同一个局域网其它或者联网的环境下在理论上也都是可以的。
需要先添加订阅者:
若退订,步骤相同,致死要选择“退订”即可。
这个表单可以放在其它订阅者站点下面,只是FORM的URL地址要正确。
进入站点首页即可看到所有订阅者的回调地址:
有了订阅者之后,需要添加博文,测试我们的订阅者。
点击提交按钮之后,在各个站点终端下即可看到:
为了演示,我们定义了两个订阅者站点: subscribeOne和subscribeTwo,一个显示所获取的数据,一个把获取的数据持久化到磁盘中。
下面看看主站点的一些代码,首先来一个传统意义上观察者模式。
需要观察的对象,即目标 BlogService.java
/**
* 博文操作
* @author yongboy@gmail.com
* @date 2010-10-18
* @version 1.0
*/
public class BlogService {
private static Set<BlogObserver> obserserList;
static {
obserserList = new HashSet<BlogObserver>();
}
public void addBlog(Blog blog) {
System.out.println("保存博文一些操作......");
// 忽略具体逻辑
System.out.println("执行通知到所有的订阅者....");
updateObsersers(blog);
}
private void updateObsersers(Blog blog) {
for (BlogObserver server : obserserList) {
server.update(blog);
}
}
public void addObserver(BlogObserver blogObserver) {
obserserList.add(blogObserver);
}
public void removeObserver(BlogObserver blogObserver) {
obserserList.remove(blogObserver);
}
public void clearObserver() {
obserserList.clear();
}
}
可以看到内含观察者的一些简单的管理操作。
还需要定义了一个观察者,接口实现:
public interface BlogObserver {
void update(Blog blog);
}
有两个具体的子类观察者,一个负责把博客的数据生成静态的文件,但这个不是重点,所以没有具体的代码附加;另外一个观察者负责把新的博文通知到所有的订阅者。
/** * 为新建的博文生成静态页面
*
* @author yongboy@gmail.com
* @date 2010-10-19
* @version 1.0
*/
public class BlogGenPageObserver implements BlogObserver {
public void update(Blog blog) {
// 具体生成代码省略
System.out.println("博文静态页面观察者开始工作......");
}
}
/** * 定义一个博客信息推送观察者
* @author yongboy@gmail.com
* @date 2010-10-18
* @version 1.0
*/
public class BlogNotifyObserver implements BlogObserver {
public void update(Blog blog) {
System.out.println("博文推送观察者开始工作......");
// 生成单篇博客的RSS
RssService rssService = new RssService(blog);
String rssContent = rssService.ouputRss();
// 通知订阅者,分发博客内容
NotifyService notifyService = new NotifyService(rssContent);
notifyService.doNotice();
}
}
当前端发布了一篇博文后,会触发这两个观察者。
订阅-发布模型,较适合于一个主端节点主动向各个订阅者节点主动推送信息,相比被动的拉模式,更为节省网络带宽以及服务器的性能。
在一个范围较大的局域网之间,彼此域之间的信息实时通知,也会是一个较好的应用。
在范围更大的互联网环境下,一个具有相当大的数量级订阅者的主机将可节省珍贵的机房带宽,经济收益不可小觑。
源代码下载