策略devise模式和状态devise模式有什么区别?

战略devise模式与国家devise模式有什么区别? 我在网上浏览了不less文章,但没有明确区分。

有人能解释一下外行的差异吗?

老实说,这两种模式在实践上是非常相似的,它们之间的定义差别往往取决于你所问的人。 一些stream行的select是:

  • 状态存储对包含它们的上下文对象的引用。 策略不。
  • 允许国家取代自己(IE:改变上下文对象的状态为别的东西),而战略则不是。
  • 策略作为parameter passing给上下文对象,而状态由上下文对象本身创build。
  • 战略只处理一个具体的任务,而国家则为上下文对象所做的一切(或者大部分事情)提供底层的实现。

一个“经典”的实现将匹配列表中的每个项目的状态或策略,但是你运行跨混合两个混合。 最终是一个主观的问题,是一个特定的更多的国家或战略。

策略模式实际上是有一个不同的实现来完成(基本上)相同的事情,所以一个实现可以取代另一个作为策略要求。 例如,您可能在策略模式中使用不同的sortingalgorithm。 对象的调用者不会根据正在使用的策略而改变,但是不pipe策略的目标是相同的(sorting集合)。

国家模式是在国家的基础上做不同的事情,让呼叫者摆脱各种可能的状态。 因此,例如,您可能有一个getStatus()方法,该方法将根据对象的状态返回不同的状态,但方法的调用者无需用不同的代码来说明每个潜在的状态。

区别在于它们解决了不同的问题:

  • 状态模式处理对象是什么 (状态或types)(in) – 它封装了状态依赖的行为,而
  • 策略模式处理对象如何执行某个任务 – 它封装了一个algorithm。

然而,实现这些不同目标的结构非常相似, 两种模式都是带有授权的组合的例子。


一些观察他们的优点:

通过使用状态模式,状态保持(上下文)类可以从知道状态或types以及可用状态或types的知识中解脱出来。 这就意味着这个类遵守开放式devise原则(OCP):类被closures,以改变什么状态/types,但是状态/types是扩展的。

通过使用策略模式,使用(上下文)类的知识如何执行特定的任务(“algorithm”)是免除的。 这种情况也造成了对OCP的遵守; 该类是closures如何执行这项任务的变化,但devise是非常开放的其他algorithm来解决这个任务的补充。
这也可能会改善上下文级别对单一责任原则(SRP)的遵守。 此外,该algorithm变得易于被其他类重用。

有人能请外行解释吗?

devise模式并不是真正的“普通人”概念,但是我会尽量使其尽可能清晰。 任何devise模式都可以在三个方面考虑:

  1. 模式解决的问题;
  2. 模式的静态结构(类图);
  3. 模式的dynamic(序列图)。

我们来比较一下状态和策略。

问题模式解决

国家被用于两种情况之一[GoF book p。 306] :

  • 对象的行为取决于其状态,并且在运行时必须根据状态改变其行为。
  • 操作具有大型的多部分条件语句,这取决于对象的状态。 这个状态通常由一个或多个枚举常量表示。 通常,几个操作将包含这个相同的条件结构。 状态模式将条件的每个分支放在单独的类中。 这使您可以将对象的状态视为一个独立于其他对象的独立对象。

如果你想确定你确实有问题的状态模式解决,你应该能够使用有限状态机模型的对象的状态 。 你可以在这里find一个应用的例子。

每个状态转换都是状态界面中的一个方法。 这意味着对于一个devise来说,在应用这个模式之前,你必须非常确定状态转换。 否则,如果添加或删除转换,则需要更改接口以及实现它的所有类。

我个人还没有find这个有用的模式。 你总是可以使用查找表来实现有限状态机(这不是一种OO方式,但是它工作得很好)。

策略用于以下[GoF book p。 316] :

  • 许多相关的类只在行为上有所不同。 策略提供了一种用许多行为之一来configuration类的方法。
  • 您需要algorithm的不同变体。 例如,您可以定义反映不同空间/时间权衡的algorithm。 当这些变体作为algorithm的类层次实现时,可以使用策略[HO87]。
  • algorithm使用客户端不应该知道的数据。 使用策略模式来避免暴露复杂的algorithm特定的数据结构。
  • 一个类定义了许多行为,这些行为在其操作中显示为多个条件语句。 将相关的条件分支移到他们自己的Strategy类别中,而不是许多条件。

在哪里应用策略的最后一个例子涉及到一个被称为替代条件与多态的重构。

总结:状态和策略解决了非常不同的问题。 如果你的问题不能用有限状态机模拟,那么可能的状态模式是不合适的。 如果您的问题不是关于封装复杂algorithm的变体,那么策略不适用。

图案的静态结构

State具有以下UML类结构:

状态模式的PlantUML类图

策略有以下的UML类结构:

策略模式的PlantUML类图

总结:就静态结构而言,这两种模式大都相同。 事实上,像这样的模式检测工具认为“模式的结构是相同的,通过自动过程(例如,不提及概念信息)禁止它们的区分 ”。

然而,如果ConcreteStates决定自己的状态转换(参见上图中的“ 可能确定 ”关联),则可能会有一个主要的区别。 这导致混凝土状态之间的耦合。 例如(见下一节),状态A决定了状态B的转换。如果上下文类决定转换到下一个具体状态,这些相关性就消失了。

模式的dynamic

正如上面的问题部分所述, 状态意味着行为在运行时会根据某个对象的状态而改变。 因此,状态转换的概念适用于有限状态机关系的讨论。 [GoF]提到过渡既可以在ConcreteState子类中定义,也可以在中心位置(如基于表格的位置)中定义。

我们假设一个简单的有限状态机:

具有两个状态和一个转换的PlantUML状态转换图

假设子类决定状态转换(通过返回下一个状态对象),dynamic看起来像这样:

PlantUML状态转换的序列图

为了显示策略的dynamic,借用一个真实的例子是有用的。

PlantUML序列图,用于策略转换

简介 :每个模式都使用多态调用来根据上下文执行某些操作。 在状态模式中,多态调用(转换)通常会导致下一个状态的改变。 在策略模式中,多态呼叫通常不会改变上下文(例如,通过信用卡支付一次并不意味着您将在下一次通过PayPal支付)。 同样,状态模式的dynamic是由它相应的fininte状态机决定的,对我来说这对于纠正这种模式的应用是必不可less的。

策略模式涉及将一个algorithm的实现从一个主机类中移走,并把它放在一个单独的类中。 这意味着宿主类不需要提供每个algorithm本身的实现,这很可能导致不干净的代码。

sortingalgorithm通常作为一个例子,因为它们都做同样的事情(sorting)。 如果将不同的sortingalgorithm放入自己的类中,则客户端可以轻松地select使用哪种algorithm,并且该模式提供了访问它的简单方法。

状态模式涉及当对象的状态改变时改变对象的行为。 这意味着主机类没有提供它可以处于的所有不同状态的行为的实现。主机类通常封装一个类,该类提供给定状态所需的function,并切换到不同的类当状态改变时。

策略表示“做”某些事物的对象,具有相同的开始和结果结果,但在内部使用不同的方法。 在这个意义上,它们类似于表示动词的实现。 国家模式OTOH使用“是”某物的对象 – 操作的状态。 虽然它们也可以表示对这些数据的操作,但它们更类似于表示名词而不是动词,并且是针对状态机量身定制的。

策略:策略是固定的,通常由几个步骤组成。 (sorting只是一个步骤,因此这是一个非常糟糕的例子,因为它是太原始了解这种模式的目的)。 这个策略中的“主要”例程是调用一些抽象方法。 例如“进入房间策略”,“主要方法”是goThroughDoor(),它看起来像:approachDoor(),if(locked())openLock(); 开门(); enterRoom(); 转(); 关门(); if(wasLocked())lockDoor();

现在,通过可能的锁门从一个房间移动到另一个房间的这个“algorithm”的子类可以实现algorithm的步骤。

换句话说,子类化策略不会改变基本的algorithm,只能是个别的步骤。

这是一个模板方法模式。 现在把属于他们的步骤(解锁/locking和打开/closures)放到他们自己的执行对象中并委派给他们。 例如,带钥匙的锁和带有密码卡的锁是两种锁。 从策略委派给“步骤”对象。 现在你有一个战略模式。

国家模式是完全不同的东西。

你有一个包装对象和包装的对象。 包装的是“国家”。 状态对象只能通过它的包装来访问。 现在,您可以随时更改包装的对象,因此包装器似乎更改其状态,甚至是其“类”或types。

例如你有一个login服务。 它接受用户名和密码。 它只有一个方法:logon(String userName,String passwdHash)。 它不是自己决定是否接受login,而是将决定委托给一个状态对象。 该状态对象通常只是检查用户/传递组合是否有效并执行login。 但是现在你可以通过一个只允许特权用户login的“检查器”来交换(例如在maintanace时间)或者一个不允许任何人login的检查器。 这意味着“检查器”表示系统的“login状态”。

最重要的区别是:当你select了一个策略,你坚持下去,直到你完成了。 这意味着你称之为“主要方法”,只要那个方法运行,你永远不会改变策略。 OTOH在系统运行期间处于状态模式的情况下,可以根据需要随意更改状态。

考虑一个处理客户呼叫的IVR(交互式语音应答)系统。 您可能需要对其进行编程以在以下方面处理客户:

  • 工作日
  • 假期

为了处理这种情况,你可以使用状态模式

  • 假期 :IVR只是回应说“ 只能在上午9点到下午5点工作日内打电话 ”。
  • 工作日 :通过将客户连接到客户服务主pipe来响应。

将客户与支持主pipe联系起来的过程本身可以通过战略模式实施,其中主pipe人员是根据以下任一方式选出的:

  • 循环赛
  • 最近最less使用
  • 其他基于优先级的algorithm

策略模式决定如何执行某些操作,状态模式决定何时执行操作。

用外行的语言,

在战略模式中,没有任何一个国家或所有国家都具有相同的国家。 所有人都有不同的执行方式,就像不同的医生以不同的方式来治疗同一病人一样的状态。

在状态模式中,主观上存在状态,如病人当前的状态(比如说高温或低温),根据其决定下一个过程(药物处方),一个状态可以导致其他状态,所以状态以状态依赖(组成技术上)。

如果我们在技术上试图理解它,基于两者的代码比较,我们可能会失去情况的主观性,因为两者看起来非常相似。

策略模式用于针对特定任务有多种algorithm,并且客户端决定在运行时使用的实际实现。

来自wiki的 UML图策略模式文章:

在这里输入图像说明

主要特征:

  1. 这是一种行为模式。
  2. 这是基于代表团。
  3. 它通过修改方法行为来改变对象的内容。
  4. 它用于在algorithm族之间切换。
  5. 它在运行时改变对象的行为。

参考这篇文章更多信息和现实世界的例子:

战略格局的现实世界范例

状态模式允许对象在其内部状态改变时改变其行为

来自wiki状态模式文章的UML图:

在这里输入图像说明

如果我们必须根据状态来改变对象的行为,那么我们可以在Object中拥有一个状态variables,并使用if-else条件块根据状态执行不同的动作。 状态模式被用来通过上下文状态实现来提供一种系统化的和失去耦合的方式来实现这一点。

请参阅这篇journaldev文章的更多细节。

来源制作和journaldev文章的主要区别:

  1. 国家战略的区别在于约束时间。 “战略”是一种“绑定一次”模式,而“国家”则更具有活力
  2. 国家战略之间的区别是有意的。 有了策略,algorithm的select是相当稳定的随着状态的变化,“上下文”对象的状态使其从“调色板”中select策略对象
  3. 上下文包含状态作为实例variables,可以有多个任务的实现可以依赖于状态,策略模式策略作为parameter passing给方法, 上下文对象没有任何variables来存储它。

这两种模式都委托给一个具有几个派生类的基类,但只有在状态模式下,这些派生类才拥有对上下文类的引用。

另一种看待它的方式是战略模式是国家模式的简单版本; 一个子模式,如果你喜欢。 这实际上取决于你是否希望派生状态保持引用回到上下文(即:你想让他们调用上下文的方法)。

更多信息:Robert C Martin(和Micah Martin)在他们的书“C#中的敏捷原则,模式和实践”中回答了这个问题。 ( http://www.amazon.com/Agile-Principles-Patterns-Practices-C/dp/0131857258

差异在http://c2.com/cgi/wiki?StrategyPattern中讨论。; 我已经使用了Strategy模式来允许在用于分析数据的整个框架内select不同的algorithm。 通过你可以添加algorithm,而不必改变整体框架及其逻辑。

一个典型的例子就是你有一个优化函数的框架。 框架设置数据和参数。 策略模式允许您在不改变框架的情况下select最强下降,共轭梯度,BFGS等algorithm。

战略和国家模式都有相同的结构。 如果您查看两种模式的UML类图,它们看起来完全相同,但其意图完全不同。 状态devise模式用于定义和pipe理对象的状态,策略模式用于定义一组可互换的algorithm,并让客户端select其中的一个。 所以Strategy模式是一个客户端驱动的模式,而Object可以pipe理它自己的状态。

这是一个相当古老的问题,但我仍然在寻找相同的答案,而这正是我所发现的。

对于状态模式,我们考虑一个“内侧播放器播放”button的例子。 当我们玩这个游戏的时候,它开始播放,并且让上下文知道它正在播放。 每当客户想要进行游戏时,他都会检查玩家的当前状态。 现在,客户端知道对象正在通过上下文对象播放的状态,所以他调用暂停状态对象操作方法。 客户端实现状态的部分以及需要执行操作的状态可以自动完成。

https://www.youtube.com/watch?v=e45RMc76884 https://www.tutorialspoint.com/design_pattern/state_pattern.htm

在策略模式的情况下,类图的排列与状态模式相同。 客户来这个安排做一些操作。 这是不同的状态,有不同的algorithm说,例如不同的分析,需要在模式上执行。 这里的客户端告诉上下文什么它想要做什么algorithm(业务定义的自定义algorithm),然后执行。

https://www.tutorialspoint.com/design_pattern/strategy_pattern.htm

两者都实现了开放式closures原则,因此开发人员有能力为状态模式和新algorithm添加新的状态。

但不同之处在于他们使用的是状态模式,用于根据对象的状态执行不同的逻辑。 在一个策略不同的逻辑的情况下。

状态在状态派生类中有一些依赖关系:就像一个状态知道其他状态一样。 例如,夏天是在任何季节状态的冬季之后,或在存款状态之后的交货状态下购物。

另一方面,Strategy没有像这样的依赖关系。 在这里,任何一种状态都可以根据程序/产品types进行初始化。