看各个模式组成的角色。
观察者模式里必须有两个角色:消息发布者(subject)和消息接受者(observer)
委托模式也有两个角色:委托者与被委托者
从行为和目的的角度来说,委托模式只是简单的将一件属于委托者做的事情,交给另外一个被委托者来处理,举个例子,如果你要写星际里面枪兵的攻击方法,可以设计为marine->attack(target)方法将真正的执行交给了marine->gun的gun->attack(target)方法:
// 代码不是什么标准代码,保证你能看懂就行
class Marine
{
public void setGun(Gun gun)
{
this->gun = gun;
}
public void attack(Target target)
{
this->gun->attack(Target target);
}
}
// Machinegun 实现了这个接口
interface Gun
{
public void attack(Target target);
}
委托一般的作用是将委托者与一些实际实现代码分离出来达成解耦的目的,试想如果需求变成枪兵可以在机枪和来复枪中切换,那么只用调用一下marine->setGun(Shotgun or Machinegun)
就行了,被委托的方法attack一点都不用改变。
嗯,其实这个例子已经是有策略模式的感觉了,所以策略模式或者说状态模式等在本质上也就是委托模式的一种具体应用
下面再说说观察者模式的行为:观察者模式就没委托模式那么直白了。观察者模式的目的是为了解决在一个由多个模块组成的应用中,其中一个模块状态改变导致其他模块也得跟着改变这个需求,其中最经典的应用就是mvc模式(这里的mvc可绝对不是指什么网站开发mvc框架那种mvc)。
还是以星际为例子,如果你使用人族,建了两个以上的给机械部队升级的建筑Terran Armory(后面简写va,va是快捷键,呃……好像我在写星际教学帖),你会发现如果你选择了其中一个va给地面重工的攻击力升级,其他的va就根本不显示给重工升攻击的图标了,其实这就可以利用观察者模式来实现:
创建一个升级管理器类UpgradingManager,如果有va被建好,将此va注册到管理器的监视者列表里面并且监听Upgrade vehicle/ship weapon/plate这4个事件:
// 当Terran Armory完成建筑后
upgradingManager->register('upgrade vehicle weapon event', terranArmory);
upgradingManager->register('upgrade vehicle plate event', terranArmory);
upgradingManager->register('upgrade ship weapon event', terranArmory);
upgradingManager->register('upgrade ship plate event', terranArmory);
当其中一个terranArmory被点击了upgrade vehicle weapon图标后,此terranArmory除了做自己该做的事情(显示升级进度条),还向UpgradingManager发出一个消息:我这里正在升级重工攻击
/* one of the */ terranArmory->notify('upgrade vehicle plate event');
当UpgradingManager收到此消息后,向所有注册了监听upgrade vehicle plate event
事件的建筑物发出消息
manager->notifyObservers('upgrade vehicle plate event');
// implementation of notifyObservers method
class UpgradingManager
{
public void notifyObservers(string eventName)
{
foreach(this->registered[eventName], function(observer) {
observer->handleEventFromManager(eventName);
});
}
}
然后全部的terranArmory都被调用了handleEventFromManger('upgrade vehicle plate event')事件,都各自隐藏了自己升级重工的图标
当然对于目前网站开发来说,也是有观察者模式的身影的,比如说许多框架提供的event dispatcher以及plugin功能,就是一个典型应用,将功能的添加和框架主流程解耦。