Answers:
坦白说,这两种模式在实践中非常相似,并且两者之间的定义差异往往会因您要求的人而异。一些受欢迎的选择是:
“经典”实现将为列表中的每个项目匹配“状态”或“策略”,但是您会在混合了两者的混合对象上运行。一个特定的国家到底是国家还是战略,这最终是一个主观的问题。
getStatus()
方法,该
方法将根据对象的状态返回不同的状态,但是方法的调用者不必对每个潜在的状态进行不同的编码。区别仅在于它们解决了不同的问题:
然而,实现这些不同目标的结构非常相似。两种模式都是通过委托进行组合的示例。
关于其优势的一些观察:
通过使用状态模式的国有控股(上下文)类是从知识松了一口气什么状态或键入这是什么国家或可用的类型。这意味着该类遵循开放式设计原则(OCP):该类因存在的状态/类型的更改而关闭,但是状态/类型对扩展开放。
通过使用策略模式,无需使用算法的(上下文)类就可以了解如何执行特定任务(“算法”)。这种情况也使OCP得以遵守;该类因执行此任务的方式的更改而关闭,但是该设计对添加其他用于解决此任务的算法非常开放。
这也可能会提高上下文类对单一职责原则(SRP)的遵守。此外,该算法变得易于用于其他类重用。
有人可以用外行的术语解释吗?
设计模式并不是真正的“外行”概念,但是我会尽力使它尽可能清晰。任何设计模式都可以从三个方面考虑:
让我们比较状态和策略。
在以下两种情况之一中使用状态[GoF书,第9页。306]:
- 对象的行为取决于其状态,并且它必须在运行时根据该状态更改其行为。
- 操作具有取决于对象状态的大型,多部分条件语句。此状态通常由一个或多个枚举常量表示。通常,几个操作将包含相同的条件结构。State模式将条件的每个分支放在单独的类中。这样一来,您就可以将对象的状态视为独立的对象,该对象可以独立于其他对象而变化。
如果要确定确实存在状态模式所解决的问题,则应该能够使用有限状态机对对象的状态进行建模。您可以在此处找到一个应用示例。
每个状态转换都是State接口中的一种方法。这意味着对于设计,在应用此模式之前必须非常确定状态转换。否则,如果您添加或删除转换,则将需要更改接口和实现该接口的所有类。
我个人还没有发现这种模式有用。您始终可以使用查找表来实现有限状态机(这不是OO方式,但效果很好)。
策略用于以下[GoF书,第 316]:
- 许多相关的类仅在行为上有所不同。策略提供了一种使用多种行为之一配置类的方法。
- 您需要算法的不同变体。例如,您可以定义反映不同时空权衡的算法。当这些变体作为算法的类层次结构实现时,可以使用策略[HO87]。
- 一种算法使用客户端不应该知道的数据。使用策略模式可避免暴露复杂的,特定于算法的数据结构。
- 一个类定义了许多行为,这些行为在其操作中显示为多个条件语句。代替许多条件,将相关的条件分支移到其自己的Strategy类中。
最后一种应用策略的情况与重构有关,称为“ 用多态替换条件”。
简介:国家和战略解决了截然不同的问题。如果您的问题无法用有限状态机建模,则可能的状态模式不合适。如果您的问题不是关于封装复杂算法的变体,那么策略就不适用。
State具有以下UML类结构:
策略具有以下UML类结构:
简介:就静态结构而言,这两种模式基本相同。实际上,图案检测工具,如这一个认为“ 的[...]的图案是相同的,由一个自动的过程禁止其区别(例如,不参照概念性信息)。结构 ”
但是,如果ConcreteStates自行决定状态转换,则可能会有很大的不同(请参见上图中的“ 可能确定 ”关联)。这导致具体状态之间的耦合。例如(请参阅下一节),状态A决定了向状态B的转换。如果Context类决定了向下一个具体状态的转换,则这些依赖项将消失。
如上面“问题”部分所述,状态表示行为在运行时根据对象的某些状态而变化。因此,如关于有限状态机的关系所讨论的,状态转移的概念适用。[GoF]提到过渡可以在ConcreteState子类中定义,也可以在集中位置(例如基于表的位置)中定义。
让我们假设一个简单的有限状态机:
假设子类决定状态转换(通过返回下一个状态对象),则动态如下所示:
为了展示策略的动态,借用一个真实的例子很有用。
简介:每个模式都根据上下文使用多态调用来执行某些操作。在状态模式中,多态调用(转换)通常会导致下一个状态发生变化。在策略模式中,多态调用通常不会更改上下文(例如,一次使用信用卡付款并不意味着您下次将使用PayPal付款)。同样,状态模式的动态性由其相应的fininte状态机确定,(对我而言)这对于正确应用此模式至关重要。
考虑一个处理客户呼叫的IVR(交互式语音响应)系统。您可能需要对其进行编程以处理以下方面的客户:
要处理这种情况,可以使用状态模式。
将客户连接到支持主管的过程本身可以使用策略模式来实现,在该策略模式中,可以根据以下任一项来选择主管:
策略模式决定“ 如何 ”执行某些动作,状态模式决定“ 何时 ”执行这些动作。
策略:策略是固定的,通常包括几个步骤。(排序仅构成一个步骤,因此是一个非常糟糕的示例,因为它太原始了,无法理解此模式的目的)。该策略中的“主要”例程正在调用一些抽象方法。例如,“进入房间策略”,“主方法”是goThroughDoor(),它看起来像:approachDoor(),如果(locked())openLock(); 开门(); enterRoom(); 转(); 关门(); 如果(wasLocked())lockDoor();
现在,用于通过可能的锁着的门从一个房间移动到另一个房间的这种通用“算法”的子类可以实现算法的步骤。
换句话说,策略的子类别不会更改基本算法,而只会更改单个步骤。
上面是模板方法模式。现在,将属于一起的步骤(解锁/锁定和打开/关闭)放入其自己的实现对象中,并委托给它们。例如,带钥匙的锁和带代码卡的锁是两种锁。将策略委托给“ Step”对象。现在您有了一个策略模式。
状态模式是完全不同的东西。
您有一个包装对象和包装的对象。包装的是“状态”。状态对象只能通过其包装器访问。现在,您可以随时更改包装的对象,因此包装程序似乎可以更改其状态,甚至可以更改其“类”或类型。
例如,您有登录服务。它接受用户名和密码。它只有一种方法:Logon(String userName,String passwdHash)。与其自行决定是否接受登录,不如将决定委托给一个状态对象。该状态对象通常仅检查用户/密码组合是否有效并执行登录。但是现在您可以通过仅允许特权用户登录(例如在维护时间)或不允许任何人登录的一种来交换“检查器”。这意味着“检查器”表示系统的“登录状态”。
最重要的区别是:选择策略后,请坚持使用它,直到完成为止。这意味着您将其称为“主要方法”,并且只要该方法正在运行,您就永远不会更改该策略。在系统运行时处于状态模式情况下的OTOH,您可以根据需要任意更改状态。
当您对特定任务有多种算法,并且客户端决定要在运行时使用的实际实现时,将使用策略模式。
来自Wiki策略模式文章的UML图:
主要特点:
有关更多信息和真实示例,请参阅此帖子:
状态模式允许对象在内部状态改变时改变其行为
Wiki状态模式文章中的UML图 :
如果必须根据对象的状态更改其行为,则可以在对象中使用状态变量,并使用if-else条件块根据状态执行不同的操作。状态模式用于通过上下文和状态实现提供一种系统的,耦合耦合的方式来实现这一目标。
有关更多详细信息,请参阅此journaldev文章。
与源制作和journaldev文章的主要区别:
这两种模式都委派给具有多个派生类的基类,但是只有在State模式下,这些派生类才拥有对上下文类的引用。
另一种看待它的方式是“策略”模式是“状态”模式的简单版本;子模式(如果您愿意)。这实际上取决于您是否希望派生状态将引用保留回上下文(即:是否希望它们在上下文上调用方法)。
有关更多信息:Robert C Martin(和Micah Martin)在他们的书“ C#中的敏捷原理,模式和实践”中回答了此问题。(http://www.amazon.com/Agile-Principles-Patterns-Practices-C/dp/0131857258)
这是一个很老的问题,但是我仍然在寻找相同的答案,这就是我所发现的。
对于状态模式,请考虑Medial Player Play按钮的示例。当我们玩游戏时,它开始播放,并使上下文知道它正在播放。每当客户想要执行播放操作时,他都会检查播放器的当前状态。现在,客户端通过上下文对象知道对象的状态正在播放,因此他调用了暂停状态对象actions方法。客户端实现状态以及需要采取何种操作状态的部分可以实现自动化。
https://www.youtube.com/watch?v=e45RMc76884 https://www.tutorialspoint.com/design_pattern/state_pattern.htm
对于策略模式,类图的排列与状态模式相同。客户来此安排进行一些操作。也就是说,代替不同的状态,有不同的算法,例如需要对模式执行不同的分析。在这里,客户告诉上下文它要执行哪种算法(业务定义的自定义算法),然后执行该算法。
https://www.tutorialspoint.com/design_pattern/strategy_pattern.htm
两者都实现了开闭原理,因此开发人员具有将新状态添加到状态模式和新算法的能力。
但是不同之处在于它们使用的是状态模式,该状态模式用于根据对象的状态执行不同的逻辑。在策略的情况下,逻辑也不同。
差异在http://c2.com/cgi/wiki?StrategyPattern中进行了讨论。我已经使用了策略模式来允许在用于分析数据的整个框架中选择不同的算法。通过它,您可以添加算法,而不必更改整体框架及其逻辑。
一个典型的例子是您拥有优化功能的框架。该框架设置数据和参数。该策略模式允许您选择算法,例如最直接下降,共轭梯度,BFGS等,而无需更改框架。
当您有一个项目时,该项目可以分为2个任务:
任务1:您可以使用两种不同的算法之一来完成:alg1,alg2
任务2:您可以使用三种不同的算法之一来完成:alg3,alg4,alg5
alg1和alg2可互换;alg3,alg4和alg5可互换。
在任务1和任务2中选择执行哪种算法取决于状态:
状态1:在任务1中需要alg1,在任务2中需要alg3
状态2:在任务1中需要alg2,在任务2中需要alg5
您可以将状态对象从状态1更改为状态2。然后您的任务将由alg2和alg5代替alg1和alg3来完成。
您可以为任务1或任务2添加更多可互换的算法。这是策略模式。
您可以在任务1和任务2中使用不同的算法组合来具有更多状态,状态模式使您可以从一种状态切换到另一种状态并执行不同的算法组合。