战略设计模式和州设计模式有什么区别?

What is the difference between Strategy design pattern and State design pattern?

战略设计模式和州设计模式之间有什么区别? 我在网上经历了不少文章,但无法清楚地看出差异。

有人可以解释外行人的条款差异吗?


老实说,这两种模式在实践中非常相似,它们之间的定义差异往往取决于你问的对象。一些流行的选择是:

  • States存储对包含它们的上下文对象的引用。策略没有。
  • 允许状态替换自己(IE:将上下文对象的状态改为其他东西),而策略则不然。
  • 策略作为参数传递给上下文对象,而状态由上下文对象本身创建。
  • 策略只处理单个特定任务,而状态为上下文对象提供的所有(或大多数)提供底层实现。

对于列表中的每个项目,"经典"实现将匹配状态或策略,但是您确实会遇到混合了两者的混合。一个特定的国家是更多的国家还是战略-Y最终是一个主观问题。


  • 策略模式实际上是有一个不同的
    完成(基本上)同样的事情的实现,以便
    一个实现可以替代战略需要的另一个。
    例如,您可能在a中有不同的排序算法
    战略模式。对象的调用者不会根据更改
    正在采用哪种策略,但无论策略如何
    是相同的(排序集合)。
  • 国家模式是基于的做不同的事情
    状态,同时让呼叫者免除负担
    适应每一个可能的状态。例如,你可能有一个
    getStatus()方法将返回基于的不同状态
    对象的状态,但方法的调用者不一定是
    编码不同以考虑每个潜在的状态。


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

  • State模式处理对象(in)的内容(状态或类型) - 它封装了依赖于状态的行为,而
  • 策略模式处理对象如何执行特定任务 - 它封装了算法。

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

对其优势的一些观察:

通过使用State模式,状态保持(上下文)类不再了解它是什么状态或类型以及可用的状态或类型。这意味着该类遵循开放式封闭式设计原则(OCP):对于所有状态/类型的更改,类是关闭的,但状态/类型对扩展是开放的。

通过使用策略模式,算法使用(上下文)类从如何执行某个任务( -"算法")的知识中解脱出来。这种情况也会导致对OCP的遵守;该类因关于如何执行此任务的更改而关闭,但该设计对于添加其他算法以解决此任务非常开放。
这也可能改善上下文类对单一责任原则(SRP)的遵守。此外,该算法变得易于被其他类重用。


Can somebody please explain in layman's terms?

设计模式并不是真正的"门外汉"概念,但我会尽量让它变得清晰。任何设计模式都可以考虑三个方面:

  • 模式解决的问题;
  • 模式的静态结构(类图);
  • 模式的动态(序列图)。
  • 让我们比较国家和战略。

    模式解决的问题

    状态用于两种情况之一[GoF book p。 306]:

    • An object's behavior depends on its state, and it must change its behavior at run-time depending on that state.
    • Operations have large, multipart conditional statements that depend on the
      object's state. This state is usually represented by one or more enumerated
      constants. Often, several operations will contain this same conditional structure. The State pattern puts each branch of the conditional in a separate class. This lets you treat the object's state as an object in its own right that can vary independently from other objects.

    如果要确保状态模式确实存在问题,则应该能够使用有限状态机对对象的状态进行建模。你可以在这里找到一个应用的例子。

    每个状态转换都是State接口中的一个方法。这意味着对于设计,在应用此模式之前,您必须非常确定状态转换。否则,如果添加或删除转换,则需要更改接口和实现它的所有类。

    我个人没有发现这种模式有用。您总是可以使用查找表来实现有限状态机(它不是OO方式,但它运行良好)。

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

    • many related classes differ only in their behavior. Strategies provide a way to configure a class with one of many behaviors.
    • you need different variants of an algorithm. For example, you might define algorithms reflecting different space/time trade-offs. Strategies can be used when these variants are implemented as a class hierarchy of algorithms [HO87].
    • an algorithm uses data that clients shouldn't know about. Use the Strategy pattern to avoid exposing complex, algorithm-specific data structures.
    • a class defines many behaviors, and these appear as multiple conditional statements in its operations. Instead of many conditionals, move related conditional branches into their own Strategy class.

    应用策略的最后一个案例与一个名为Replace conditional with polymorphism的重构有关。

    总结:国家和战略解决了截然不同的问题。如果您的问题无法使用有限状态机建模,则可能的状态模式不合适。如果您的问题不是封装复杂算法的变体,那么策略不适用。

    图案的静态结构

    State具有以下UML类结构:

    PlantUML class diagram of State Pattern

    策略具有以下UML类结构:

    PlantUML class diagram of Strategy Pattern

    总结:就静态结构而言,这两种模式大多相同。实际上,像这样的模式检测工具就是考虑到"结构的"
    [...]模式是相同的,禁止他们的
    通过自动过程进行区分(例如,不参考
    概念信息。)"

    但是,如果ConcreteStates决定自己的状态转换(参见上图中的"可能确定"关联),则可能存在重大差异。这导致具体状态之间的耦合。例如(参见下一节),状态A确定转换到状态B.如果Context类决定转换到下一个具体状态,那么这些依赖关系就会消失。

    动态的模式

    如上面的问题部分所述,State暗示行为在运行时会根据对象的某些状态而更改。因此,正如有限状态机的关系所讨论的那样,应用状态转换的概念。 [GoF]提到过渡可以在ConcreteState子类中定义,也可以在集中位置(例如基于表的位置)定义。

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

    PlantUML state transition diagram with two states and one transition

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

    PlantUML sequence diagram for state transitions

    为了展示战略的动态,借用一个真实的例子是有用的。

    PlantUML sequence diagram for strategy transitions

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


    策略模式涉及从托管类移动算法的实现并将其放在单独的类中。这意味着主机类不需要提供每个算法本身的实现,这很可能导致不洁的代码。

    排序算法通常用作示例,因为它们都做同样的事情(排序)。如果将每个不同的排序算法放入其自己的类中,则客户端可以轻松选择要使用的算法,并且该模式提供了一种访问它的简单方法。

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


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


    考虑处理客户呼叫的IVR(交互式语音应答)系统。您可能希望对其进行编程以处理客户:

    • 工作日
    • 假期

    要处理这种情况,您可以使用状态模式。

    • 假期:IVR只是回答说"只能在上午9点到下午5点之间的工作日打电话"。
    • 工作日:通过将客户与客户服务主管联系起来。

    将客户与支持主管联系起来的过程本身可以使用策略模式来实现,其中基于以下任一方式挑选高管:

    • Round Robin
    • 最近最少使用
    • 其他基于优先级的算法

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


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

    现在,通过可能锁定的门从一个房间移动到另一个房间的这种通用"算法"的子类可以实现算法的步骤。

    换句话说,对策略进行子类化不会改变基本算法,只会改变单个步骤。

    上面是模板方法模式。现在将属于一起的步骤(解锁/锁定和打开/关闭)放入它们自己的实现对象中并委托给它们。例如。带钥匙的锁和带代码卡的锁是两种锁。从策略委派给"Step"对象。现在你有了一个战略模式。

    状态模式是完全不同的。

    你有一个包装对象和包装对象。包裹的是"状态"。只能通过其包装器访问状态对象。现在你可以随时更改包装对象,因此包装器似乎改变了它的状态,甚至是它的"类"或类型。

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

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


    当您为特定任务使用多个算法时,将使用策略模式,并且客户端决定在运行时使用的实际实现。

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

    enter image description here

    主要特点:

  • 这是一种行为模式。
  • 它基于授权。
  • 它通过修改方法行为来改变对象的内容。
  • 它用于在算法族之间切换。
  • 它在运行时更改对象的行为。
  • 有关更多信息和实际示例,请参阅此帖子:

    战略模式的现实世界范例

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

    来自wiki State模式文章的UML图:

    enter image description here

    如果我们必须根据其状态更改对象的行为,我们可以在Object中有一个状态变量,并使用if-else条件块根据状态执行不同的操作。状态模式用于提供通过上下文和状态实现实现此目的的系统和丢失耦合方式。

    有关更多详细信息,请参阅此journaldev文章。

    与sourcemaking和journaldev文章的主要区别:

  • 国家与战略之间的区别在于约束时间。该战略是一对一的模式,而国家更具活力。
  • 国家与战略之间的区别在于意图。使用Strategy,算法的选择相当稳定。使用State,"context"对象状态的改变使其从Strategy对象的"调色板"中进行选择。
  • 上下文包含状态作为实例变量,并且可以有多个任务,其实现可以依赖于状态,而策略模式策略作为参数传递给方法,上下文对象没有任何变量来存储它。

  • 用外行的语言,

    在策略模式中,没有状态或所有状态都具有相同的状态。
    所有人都有不同的执行任务的方式,就像不同的医生以不同的方式对待同一患者的相同疾病。

    在状态模式中,主观上存在状态,如患者的当前状态(例如高温或低温),基于该状态将决定下一个行动(药物处方)。并且一个状态可以导致其他状态,因此存在状态陈述依赖性(技术上的组成)。

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


    这是一个非常古老的问题,但我仍然在寻找相同的答案,这就是我发现的。

    对于状态模式,我们可以考虑Medial Player Play按钮的示例。当我们玩游戏时,它开始播放并使上下文意识到它正在播放。每次客户想要执行游戏操作时,他都会检查玩家的当前状态。现在客户端通过上下文对象知道对象的状态,因此他调用了暂停状态对象的动作方法。实现状态的客户端部分以及需要执行操作的状态可以自动化。


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

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

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

    两者都实现了开放关闭原则,因此开发人员可以向状态模式和新算法添加新状态。

    但不同之处在于它们的用途是用于根据对象的状态执行不同逻辑的状态模式。并且在战略不同的情况下。


    State在状态派生类中带有一点依赖性:就像一个状态知道其后的其他状态。例如,夏季来自冬季之后的任何季节状态,或者在存款状态之后的交付状态购物。

    另一方面,策略没有像这样的依赖。这里,可以基于程序/产品类型初始化任何类型的状态。


    两种模式都委托给具有多个派生类的基类,但只有在State模式中,这些派生类才能将引用保存回上下文类。

    另一种看待它的方法是策略模式是State模式的简单版本;一个子模式,如果你愿意。这实际上取决于您是否希望派生状态将引用保留回上下文(即:您是否希望它们在上下文中调用方法)。

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


    简而言之,通过策略模式,我们可以动态设置一些行为,使用状态模式,我们可以肯定,一个对象将通过其状态的变化在内部改变其行为。


    不同之处在http://c2.com/cgi/wiki?StrategyPattern中讨论。我使用策略模式允许在用于分析数据的整体框架中选择不同的算法。通过它,您可以添加算法,而无需更改整体框架及其逻辑。

    一个典型的例子是你有一个优化功能的框架。框架设置数据和参数。策略模式允许您在不改变框架的情况下选择算法,例如最晚下降,共轭梯度,BFGS等。


    战略和国家模式都具有相同的结构。如果你看两个模式的UML类图,它们看起来完全相同,但它们的意图完全不同。状态设计模式用于定义和管理对象的状态,而策略模式用于定义一组可互换的算法,并允许客户端选择其中一个。因此,策略模式是客户端驱动的模式,而Object可以管理状态本身。


    当你有一个项目,可以分为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中,您可以拥有更多具有不同算法组合的状态。状态模式允许您从一种状态切换到另一种状态并执行不同的算法组合。