状态模式和策略模式都是行为型设计模式,它们的主要目标都是将变化的行为封装起来,使得程序更加灵活和可维护。之所以将状态模式和策略模式进行比较,主要是因为两个设计模式的类图相似度较高。但是,从状态模式和策略模式的应用场景来说,两个模式存在显著的差异。接下来将一步步说明。
状态模式
状态模式是一种行为设计模式,允许一个对象在其内部状态改变时改变它的行为,使其看起来修改了自身所属的类。状态模式的本质是将状态对象化处理。其类图表示如下:
状态模式主要适用于状态数量非常多且状态相关的代码会频繁变更的话,或代码中包含大量与对象状态有关的条件语句,或基于条件的状态机转换中存在许多重复代码等场景。通过将状态相关的代码抽取到状态类中,实现了状态与状态上下文的解耦。这样,就可在不修改已有状态类和上下文的前提下,引入新状态,这符合面向对象的开闭原则。但是,状态模式因为将状态对象化处理,也会带来代码复杂度上升的问题。如果只有很少的几个状态,或者状态很少发生变化,则不建议使用状态模式。此外,虽然引入新状态可以不用修改已有状态类和上下文,但是增加新的状态类需要修改那些负责状态转换的源代码,这无疑违背“开闭”原则。
策略模式
策略模式也是一种行为设计模式,策略模式通过定义一组可相互替换的算法,实现将算法独立于使用它的用户而变化。简单来说,就是定义一系列算法,然后将每一个算法封装起来,并使它们可相互替换。其类图表示如下:
从策略模式的类图可知,策略模式就是抽象了算法,并通过策略上下文完成了具体算法策略的选择。
策略模式适用于一个行为有多种实现、或为了消除复杂的条件运算符(如多重的条件选择语句),实现同一算法在不同变体中切换等场景。策略模式将算法的实现独立出来,实现了在不修改原有系统的基础上选择算法或行为,这符合开闭原则。此外,策略模式还可消除多重条件语句,降低代码复杂度。与其他设计模式一样,策略模式因为需要引入新的算法接口和实现,会带来代码复杂度上升的问题。策略模式虽然可以在不修改原有系统的基础上选择算法或行为,但是新增一个算法实现,仍需要修改策略上下文。而且,对于条件语句少的场景或算法极少变化的场景下,没有必要引入策略模式。
状态模式和策略模式的对比
无论状态模式,还是策略模式,都是创建型模式。其主要职责都是将变化的行为封装起来,使得程序更加灵活和可维护。状态模式主要用于处理一个对象在其内部状态改变时,需要改变其行为的情况。状态模式通过将状态相关的代码抽取到状态类中,实现了状态与状态上下文的解耦。在对象有多个状态,且状态之间存在复杂的转换逻辑时,状态模式可以简化代码和提高可维护性。而策略模式通过定义一组可相互替换的算法(算法簇),实现将算法独立于使用它的用户而变化。从功能上来说,状态模式和策略完全是两个完全不相似的设计模式。
接下来重点分析状态模式和策略模式的结构。从类图结构上看,策略模式和状态模式很相似。都有Context,且这个Context都依赖抽象的状态或策略。且抽象的状态或策略都有多种实现。但是,两个设计模式也仅仅是类图相似,其职责完全不同。在状态模式中,StateContext保存了State对象(具体状态对象)的引用,并将所有与该状态相关的工作委派给它。而在策略模式中,StrategyContext维护指向Strategy对象(具体策略)的引用,且仅通过策略接口与该对象进行交流。在状态模式中,多个State对象可能存在交互(如从状态A切换到状态B)。而在策略模式中,每个Strategy对象都不需要感知其他Strategy对象的存在(每个Strategy子类都是行为的封装)。策略模式偏重于可替换的算法以及这些算法在对应的Context中的正确调用,而状态模式则偏重于各状态自身的逻辑运行以及各个状态间的切换和初始化。
对比发现,虽然状态模式和策略模式虽然都是行为型设计模式,且类图相似度极高,但是两个策略无论在使用场景、还是对象的职责上,都存在明显的差异,在选用时很容易区分。
参考
https://yiyan.baidu.com/ 文心一言
《设计模式:可复用面向对象软件的基础》 Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides 著 李英军, 马晓星 等译