为什么应该弃用observer模式



我注意到,我的依赖注入、观察者模式繁重的代码(使用Guava的EventBus)通常比我过去写的没有这些功能的代码更难调试。尤其是在试图确定何时以及为什么调用观测器代码时。

马丁·奥德斯基和朋友们写了一篇很长的论文,题目特别诱人,";弃用观察者模式";我还没来得及读。

我想知道观察者模式到底出了什么问题,以及如何更好地引导如此聪明的人写这篇论文。

首先,我确实在这里找到了对这篇论文的一个(有趣的)评论。

直接从论文中报价:

为了说明观察者模式的精确问题,我们从一个简单而普遍的例子开始:鼠标拖动。以下示例跟踪鼠标在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]中定义的模式通常违反了令人印象深刻的一系列重要的软件工程原理:

副作用观察者促进副作用。由于观察员是无状态的,我们通常需要其中几个来模拟拖动示例中的状态机。我们必须拯救所有相关观察员都可以访问的状态例如在上面的变量CCD_ 2中。

封装由于状态变量path脱离作用域在观察者中,观察者模式破坏了封装。

可组合性多个观察者形成松散集合处理单个关注点(或多个,见下一点)。由于在在不同的时间点,我们不能,例如,很容易将它们全部处理掉。

关注点分离上述观察者不仅追踪鼠标路径,但也调用绘图命令,或更一般地说,在相同的代码位置。通常最好将构建路径并显示路径的关注点。,如在模型视图控制器(MVC)[30]模式中那样。

可扩展性我们可以在例如,为自己发布的路径创建一个类路径更改时发生的事件。不幸的是,没有保证观察者模式中的数据一致性。让我们假设我们将创建另一个事件发布依赖于我们原始路径的变化的对象,例如。,表示路径边界的矩形。而且让观察者倾听路径及其边界,以便绘制带边框的路径。这观察员将需要手动确定边界已更新,如果未更新,则推迟绘制活动否则,用户可能会在屏幕尺寸不对(小故障)。

一致性安装不同观察员的不同方法降低代码一致性。

抽象示例中的抽象级别较低。它依赖于控件的重量级接口类,该类提供的不仅仅是要安装的特定方法鼠标事件观察员。因此,我们不能抽象超过精确的事件源。例如,我们可以让用户通过点击escape中止拖动操作按键或使用不同的指针设备,如触摸屏幕或图形平板电脑。

资源管理观察者的一生需要由客户端管理。由于性能原因,我们希望只在拖动操作。因此,我们需要显式安装并卸载鼠标移动观测器,我们需要记住安装点(上面的控制)。

语义距离最终,这个例子很难理解因为控制流是反向的太多的样板代码增加了语义程序员意图和实际代码。

[25]E.Gamma、R.Helm、R.Johnson和J.Vlissides。设计模式:可重用的面向对象软件的元素。马萨诸塞州波士顿,Addison-Wesley Longman出版有限公司,股份有限公司,美国,1995年。是0-201-63361-2。

我相信Observer模式具有解耦事物所带来的标准缺点。Subject与Observer脱钩,但你不能只看它的源代码就知道是谁在观察它。硬编码的依赖关系通常更容易阅读和思考,但更难修改和重用。这是一种权衡。

至于本文,它并没有讨论Observer模式本身,而是讨论它的一个特殊用法。特别是:每个被观察的对象都有多个无状态Observer对象。这有一个明显的缺点,即单独的观察者需要相互同步("由于观察者是无状态的,我们通常需要几个来模拟拖动示例中的状态机。我们必须拯救所有相关观察员都可以访问的状态例如在上面的可变路径中")

上面的缺点是这种用法特有的,而不是Observer模式本身。您还可以创建一个实现所有OnThisOnThatOnWhatever方法的单个(有状态!)观察者对象,从而消除在许多无状态对象之间模拟状态机的问题。

我将简短介绍,因为我是这个主题的新手(还没有读过那篇特定的文章)。

观察者模式在直觉上是错误的:被观察的对象知道谁在观察(主体<>--观察者)。这与现实生活(在基于事件的场景中)相反。如果我尖叫,我不知道是谁在听;如果闪电击中地板。。。闪电直到击中才知道有地板!。只有观察者知道他们能观察到什么。

当这种事情发生时,软件就会变得一团糟——因为它是按照我们的思维方式构建的。就好像对象知道其他对象可以调用他的方法一样。

国际海事组织的一个层面,如"环境",是负责处理事件并通知受影响的人。(OR混合事件和该事件的生成器)

事件源(主题)向环境生成事件。Environment将事件传递给Observer。观察者可以登记影响他的事件类型,或者它在环境中实际定义。这两种可能性都是有道理的(但我想说得简短一点)。

在我的理解中,观察者模式将环境和;主题

PS。讨厌把抽象的想法放在段落里!:P

最新更新