“责任链模式”和“策略模式”的区别是什么?

19
我提出这个问题是因为我几天前在SO上提出了另一个问题
我不得不解决一个特定的问题,在得到两个回复后,我意识到两个模式可以帮助解决这个问题(以及任何其他类似的问题)。
  1. 责任链模式
  2. 策略模式

我的问题是:

这些模式之间究竟有什么区别?

8个回答

32

它们非常不同。

策略模式是关于具有通用接口,您可以使用该接口来提供算法的不同实现,或者几个具有某些共同依赖性的算法或逻辑片段。

例如,您的CollectionSorter可以支持一个SortingStrategy(归并排序,快速排序,冒泡排序)。它们都具有相同的接口和目的,但可以执行不同的操作。

在某些情况下,您可能决定在内部确定策略。也许排序器基于集合大小等启发式方法。大多数时候确实是从外部注入的。这时模式真正发挥作用:它为用户提供了覆盖(或提供)行为的能力。

此模式是现在无处不在的控制反转的基础。完成经典模式后,学习下一步。

责任链模式涉及拥有一系列对象,这些对象通常从更详细到更通用。链中的每个部分都可以提供答案,但它们具有不同的详细级别。

GOF的流行示例是上下文帮助系统。当您单击桌面应用程序中的组件时,会显示哪个帮助?链中的第一项可以查找您单击的组件的帮助。链中的下一个可以尝试为整个包含对话框显示帮助。应用程序模块的下一个...等等。

看起来您还没有阅读GOF的“设计模式”经典著作,但是应该去阅读。


谢谢你的回答。让CollectionSorter选择使用哪种策略是否有效,或者根据某些标准在其他地方以编程方式执行,而不是用户执行此操作?因为我看到的所有关于策略模式的示例中,用户总是使用特定的策略调用调用。 - Oscar Mederos
@Oscar Mederos 您可以使用责任链模式和策略模式。您可以将一组策略链接在一起,以便给定的策略能够基于“某些共同依赖项”处理所需的行为,就像Konrad Garus所指出的那样。例如,Spring框架在Validator接口上使用此类场景-请参见http://docs.spring.io/spring-framework/docs/2.5.x/api/org/springframework/validation/Validator.html-,它根据应该验证的类选择策略。 - Arthur Ronald

13
在责任链模式中,每个对象有责任将调用传递给链中的下一个对象,如果该对象无法处理它。
在策略模式中,所有对象都具有相同的接口,但某些外部力量必须提供要使用哪个接口。

1
我喜欢这个!不过度复杂,这使得它更加清晰易懂。 - Chase Florell

3
如其名,责任链模式会为请求创建一系列接收者对象的链。这种模式基于请求类型来解耦发送者和接收者。此模式属于行为模式。在该模式中,通常每个接收者都包含对另一个接收者的引用。
责任链模式是指“通过让多个对象有机会处理请求来避免将请求的发送者与接收者耦合”。例如,ATM在发放现金过程中使用责任链设计模式。
策略模式是一种行为设计模式,它允许您定义一组算法,并将每个算法放入单独的类中,使它们的对象可互换。
在策略模式中,我们创建代表各种策略的对象以及一个上下文对象,其行为根据其策略对象而变化。策略对象会更改上下文对象的执行算法。

2
最显著的区别是实现的语义行为不同。
责任链模式可以将0到所有的职责应用于输入,并且每个职责都决定是否对输入进行操作,然后将其传递下去。这是一种过程式模式,因为所有职责都可能被应用。
想象一下,将一系列过滤器应用于输入,每个过滤器在将其传递给下一个过滤器之前决定是否应该处理输入。
策略模式只能将一个策略应用于输入。这通常是一种创造性的模式,因为只应用单个策略。
想象一下,根据输入从数据库驱动程序列表中选择使用哪个数据库驱动程序以及如何创建连接,一旦找到正确的驱动程序,它就是唯一使用的。
两者都可以作为列表实现,使用访问者模式,不同之处在于当策略返回true时停止“访问”。
策略模式也可以作为一个Map实现,其中Key是一个Predicate,可以决定结束键的迭代,然后只需获取Value,这就是你的结果。

2
大多数模式在代码(甚至UML)中看起来非常相似,但模式通常集中于上下文、责任和它们打算解决的特定问题,而不是特定的源代码。两者都分离了不同的东西并出于不同的原因。
责任链模式将发送请求的责任与处理请求的责任分开。可以有许多类可以处理相同类型的请求(这些类通常实现相同的接口),但该模式允许请求从一个类(在链中)传递到另一个类,直到最适合处理请求的处理程序获得它并负责处理请求(或直到空处理程序获得它并指示链的结尾)。如果允许错误的处理程序处理请求,则结果可能永远不正确。
策略模式涉及处理方法或算法选择。以计算一些样本的平均值为例。在给定的上下文中,任何算法都可能始终正确(例如,所有具有策略的类都执行相同的操作:计算平均值),但计算平均值的方式或策略因类而异,策略模式允许您以分离的方式选择要使用的策略。
现在将其与责任链模式进行比较,在责任链中可能会有一个计算平均值的请求,其中有一个处理程序负责计算平均值,还可能有另一个请求计算标准差,其中有另一个处理程序负责计算标准差。因此,在任何情况下,计算平均值的请求都不会由除最合适的处理程序之外的任何其他处理程序处理。而在策略中的任何类都可以计算平均值,如果您不喜欢某个类计算平均值的方式,可以将一个策略替换为另一个策略。
实现这些的方式在程序员之间可能会有所不同,但应该通过相同的单元测试。注意:责任链的某些成员可能使用策略模式来完成其工作。

1
您可以将职责链视为策略模式的一种特殊情况,它更通用。正如Konrad所述,您使用基于模式的解决方案来解决的问题是不同的。
顺便说一下,在几乎所有GOF模式中都可以找到某种类型的策略。

0

策略模式:

  1. 它是一种行为模式
  2. 它基于委托
  3. 通过修改方法行为,它改变了对象的内部实现
  4. 它用于在算法族之间切换
  5. 它在运行时更改对象的行为。从算法族中选择一个算法。

请查看此SE问题以获取策略示例:

策略模式的真实世界示例

责任链模式:

责任链模式是一种设计模式,由命令对象的源和一系列处理对象组成。每个处理对象包含定义它可以处理的命令对象类型的逻辑;其余的命令对象将传递给链中的下一个处理对象。

关键点:

  1. 多个对象可以处理请求,处理程序可能不是特定的对象
  2. 在责任链模式中,请求将通过一系列对象传递,直到被处理。但在策略模式中,将从算法族中在运行时选择一个特定的算法。

现实世界的例子:在公司中,指定角色有特定的限制来处理采购请求。如果担任指定角色的人没有足够的权限来批准采购账单,他将把命令/请求转发给他的继任者,后者具有更多的权限。这个链条将继续,直到命令被处理。

请参考下面有用的SE问题/链接

责任链模式

oodesign的责任链模式

sourcemaking的责任链模式


0

策略模式是一种业务级别的设计模式,是如何实现给定目标/数据结果的标准化接口方式。

责任链模式更多地是一种实现模式 - 描述如何处理数据,而不是关注策略的目标。

例如:

假设我们有一个俱乐部有100名年轻游泳者,每年要选出10人团队参加常规国家比赛。比赛的形式不同 - 有些比赛有更多的仰泳比赛,有些则有更多的接力比赛,等等......这意味着您必须应用不同的团队选择策略。

因此,您有四种专用策略,每种针对不同的比赛项目。

在代码中,它可以看起来像:

RankingsSet rankedClubSet = getSwimmersRankings(SwimmersSet allSwimmers)
SwimmersSet teamOf10 = selectTeamForCompetion(RankingsSet rankedClubSet, CompetionSelectionStrategy strategy) 

但如何获得排名?

你只需询问教练组的意见:

游泳者(自我评估) -> 生理学家 -> 生物更新训练师 -> 医生 -> 游泳教练 -> 队友 -> 教师 -> 父母... ----> 策略/资格委员会

这是一项责任链。顺序很重要...医生在未经生理学家评估之前无法评估游泳者,如果主教练拒绝游泳者,则父母的意见并不重要...

排名信息在从一个处理器传递到下一个处理器时合并,某些处理器的数据被隐藏,其他处理器可以用附加注释进行装饰...

有趣的是,在这种情况下,作为俱乐部的叙述者,您可以考虑两个层面的战略:

  1. 纯计算排名数字以确定比赛的10人团队,即CompetionSelectionStrategy
  2. 整个选择过程 - 收集排名,调整专用策略,问题如何看待运动心理学家的意见等。

但在“设计模式”术语中,策略模式只有1种。

第2点太大了,无法通过单个设计模式进行分析。

重要的是要记住,在设计模式分析中,您应该专注于相当小的功能块,以便您可以轻松地识别单个模式并实现它。

当功能块太大时,自动涉及许多模式和它们之间的关系,讨论变得混乱,有些人对某些模式如此固执,以至于他们无处不见。识别设计模式基于缓慢的分析和仔细的问题分解。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接