从the paper直接引用:
为了说明观察者模式, 我们用一个简单的且普遍存在的例子开始的精确问题:鼠标拖动。 以下示例在拖动操作期间跟踪该 鼠标的运动在一个Path
对象和显示在屏幕上 它。为了简单起见,我们使用Scala闭包 作为观察者。
var path: Path = null
val moveObserver = { (event: MouseEvent) =>
path.lineTo(event.position)
draw(path)
}
control.addMouseDownObserver { event =>
path = new Path(event.position)
control.addMouseMoveObserver(moveObserver)
}
control.addMouseUpObserver { event =>
control.removeMouseMoveObserver(moveObserver)
path.close()
draw(path)
}
上面的例子,当我们将认为如在[25]一般而言,违反了重要的软件工程原理的令人印象深刻的 阵容限定的观察者 图案:
副作用观察员促进副作用。由于观察者 是无状态的,我们经常需要其中的几个来模拟 状态机,如拖动示例中所示。我们必须保存 的状态,所有参与的观察者都可以访问 ,例如上面的变量path
。
封装作为状态变量path
逸出的观察员的范围 ,观察者模式打破封装。
组合性多个观察者形成以单一关注处理对象的松散集合 (或多个, 见下点)。由于多个观察者在不同的时间安装在不同的点上,所以我们不能,例如, 可以轻松地将它们全部处理掉。的顾虑
分离上面观察员不仅跟踪 鼠标路径还要调用的绘制命令,或 更一般地,包括在同一 代码位置的两个不同的关注。通常最好分开构建路径并显示它的 问题,例如 ,如模型 - 视图 - 控制器(MVC)[30]模式。
Scalablity我们可以通过为自己发布 事件时的路径改变路径,创建一个类实现我们 例如关注点分离。不幸的是,在观察者模式中没有数据一致性的保证 。 让我们假设我们将创建另一个事件,发布 对象,该对象取决于我们原始路径中的更改,例如,表示我们路径边界的矩形,即 。另外, 考虑观察者聆听路径及其边界中的更改以绘制框架路径。这个观察者将手动确定 范围是否已经更新,如果不是,则延迟图形操作 。否则,用户可能会在屏幕上观察 的大小错误(毛刺)的屏幕。
一致性不同的方法来安装不同的观察者 降低代码的一致性。
抽象该示例中抽象层次较低。 它依赖于控件的一个重量级界面,它提供的不仅仅是特定的方法来安装 鼠标事件观察者。因此,我们无法通过精确的事件来源摘要 。例如,我们 可以通过点击转义键 或使用不同的指针设备(例如触摸屏或图形输入板)来中止拖动操作。
资源管理观察员的生命期需要由客户管理的 。由于性能方面的原因,我们只想在 拖动操作期间观察鼠标移动事件 。因此,我们需要明确安装 并卸载鼠标移动观察器,我们需要 记住安装点(上面的控件)。
语义距离最终,例如是很难理解 因为控制流被反转,其在增加了程序员意图和 实际的代码之间的语义距离 太多样板代码导致 。
E. Gamma,R. Helm,R. Johnson和J. Vlissides。设计 模式:可重用的面向对象软件的元素。 Addison-Wesley Longman Publishing Co.,Inc.,Boston,MA, USA,1995.ISBN 0-201-63361-2。
也在这里讨论过...... http://lambda-the-ultimate.org/node/4028 – 2012-07-30 21:33:03