与观察者模式相比,委托模式有什么优势?


9

委托模式中,只有一个对象可以直接侦听另一对象的事件。在观察者模式中,任意数量的对象都可以侦听特定对象的事件。当设计一个需要通知其他对象事件的类时,为什么要在观察者模式上使用委托模式?我认为观察者模式更加灵活。您现在可能只有一个观察者,但是将来的设计可能需要多个观察者。


4
“委托模式”是什么意思?如果您在谈论诸如.net的委托之类的内容,则可以根据需要拥有任意数量的订阅者。
CodesInChaos

Answers:


7

本身没有委托模式。我假设您的意思是“ 委派模式”

据我了解,它们彼此完全相反,并且用于不同的目的。

通常,使用观察者模式,任意数量的观察者对象将侦听第二个对象上的事件并对该事件采取行动。第二个对象不了解其侦听器。它只是呼唤他们。

委托对象传递给第二个对象,该对象直接在委托上调用方法。而这正是您要寻找的优势。它没有向多个侦听器发送单个消息,而是具有对单个对象(在给定时间)的完全控制。另请参阅控制反转


6

您看错了东西。观察者看到发生了特定事件。它不会影响它,也不会拥有它。委托人处理特定事件,并拥有处理程序的所有权,即使委托人拥有事件的接口也是如此。


1
委托人实际上不过是事件的观察者。委托不需要任何“处理”。它可以安全地执行任何操作,并且不会(或至少不应)影响触发事件的实例。
Marjan Venema

5
@MarjanVenema-如果对象A没有将事件的责任委派给对象B,则您没有使用委托模式:您只使用了一个观察者模式的观察者模式。
Telastyn

是的,这就是我的想法。我理解委托是“ OnWhatever”事件的订户要使用的事件签名类型。显然,C#中的委托不是像Delphi这样的单用户。
Marjan Venema

@Marjan Venema“代表实际上只是事件的观察者。” -这取决于您在说什么语言。在目标C中,某些委托负责提供数据(例如,数据委托),而缺少数据委托的对象没有要提供的数据。在那些情况下,发生了委派,这与仅观察某些事物的行为不同。
occulus

1
@occulus:感谢您的澄清。可惜的是,语言在术语上无法达成共识...当人们对于同一个单词理解不同的事物时,以语言不可知的方式谈论编程会变得有些困难。
Marjan Venema

4

这是几个权衡的问题。

权衡:

  • 灵活性(就具有n> 1个代表/观察者而言)
  • 发送消息的费用
  • 弹性(维持代表/观察者不可用的能力)
  • 使用方便

委托模式:

  • 不太灵活-不能添加1个以上的委托(这意味着某种形式的“多委托”,即观察者模式)
  • 发送消息很便宜,O(1)-与调用任何其他函数或方法相同的成本(无需查找,消息队列或其他基础结构)
  • 通常没有弹性-委托人会在场并完成他们的工作,即,如果不知道委托人,发送者往往会失败
  • 易于掌握,易于实施

观察者模式:

  • 非常灵活-设计需要增加n> 1个观察者
  • 发送消息的成本由观察者的数量O(n)隐含,即n个观察者花费n的时间和消息(至少在幼稚的实现中)
  • 通常具有弹性-通常不会要求观察者对发送者进行任何工作。即使没有观察者,发送者也不会受到影响
  • 可能变得相当复杂,尤其是观察者希望对消息做出反应(顺序重要吗?哪个观察者以哪种方式做出响应?)

1

据我了解,委托模式在其他语言(例如Delphi)中称为事件处理程序机制。这样,它只是观察者模式的一个实现,但有一个主要限制:一次只能一个监听者。

事件处理程序或委托的缺点很明显:只有一个观察者。

优势不是那么明显:性能。使用观察者模式,您可以添加许多观察者。当发生需要通知观察者的事件时,您将需要枚举观察者并将通知发送给每个观察者。这会很快使任何观察到的实例陷入困境,特别是当需要通知的事件数量也很大时。


??C#委托只是方法的签名(作为变量类型,例如,int (*my_int_f)(int)在C中)。我一直认为,通过使它更像struct / enum来使它们更容易理解。事件是使用单个委托签名的灵活侦听器数组的挂钩。您可以在没有事件的情况下做到这一点(这就是为什么我认为OP表示委派模式的原因,这是非常不同的),但是这种语言使您变得更轻松。
pdr 2012年

嗯。尚不熟悉C#。我理解委托与Delphi中“ OnWhatever”事件所使用的事件签名类型等效。那么C#事件可以由多个侦听器订阅吗?
Marjan Venema

通用Action <T>是一个委托。它与事件无关,它是一个被传递的变量。是的,多个侦听器可以侦听一个事件。
pdr 2012年

好的,谢谢,希望我能坚持下去... :-)拿出C#参考并更多地关注事件机制。
Marjan Venema

1

这是一篇过时的文章,但无论如何我都会很高兴,因为其他答案都没有涉及使用任何一种模式时发生的情况,它们似乎更多是关于理论而非实践。

委派和观察员如何工作

通过委派,委托人可以精确地选择在潜在事件源创建后谁将对特定事件做出响应。您可以将这个侦听器视为一个观察者。在观察者模式的情况下,观察者会在感觉到的时候选择观察者。因此,在观察者与委派之间的依赖关系是相反的。使用观察者模式,可以将报纸和订阅者视为观察者。观察者可以控制何时创建关系。与代表团一起思考一个雇员和一个雇主。雇主控制何时建立关系以及确切地由谁负责特定事件。员工通常无法选择他们正在执行的任务。

有人认为代表团可以有一名观察员,但我认为两者之间的真正区别在于事件处理的分配方式。您将永远不会看到代表注册事件。直到事件发生并且委托者对此事件调用一个公共方法之前,它永远都不会知道它的事件处理方式。

委托优势

这种图案非常刚性,在大多数常规设计中,它更简单且通常更坚固。它迫使您在初始化潜在事件的源时预先声明事件处理程序。如果您需要某人指挥交通,您可以在开阔街道之前指定一名交通总监。就观察员而言,您可以让交通警察随时选择何时引导交通。

委派劣势

这种设计的缺点是它不灵活。如果您正在实施一些用于订阅报纸的代码,则报纸/代理人将必须准确地确定谁可以在创建新闻后的第二个月阅读新闻故事。通过观察者模式,他们可以在以后的任何时间进行注册,而报纸只需要知道有新人签约即可。

何时选择委派?

当您确定需要一个特定的观察者并且没有理由要更改观察者时,僵化的委派模式设计将是有益的。

例如,您需要一个类/对象来处理针对特定错误的弹出窗口。没有太多原因为什么需要在运行时切换谁正在处理特定错误,因此将“内存不足”错误委托给单个实体是有意义的。创建一个潜在的处理程序数组,然后让这些处理程序注册“内存不足”错误没有多大意义;这将是在这种情况下使用观察者模式的示例。在运行时,您可能想更改变量事件的调用方法或调用“委托”的方法,但是在运行时将事件处理程序换为特定事件是不正常的。

像您在观察者模式中那样交换代表不是没有可能,这只是很复杂。在现实世界中,您可能想交换交通警察,以便由新的委托人来处理交通。有人可能会争辩说,一种更好的设计会使原委派成为一个警察局,而不是一个警察,但我离题了。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.