设计模式之状态模式
状态模式(State Pattern)属于行为型模式。
状态模式的定义
允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
状态模式主要解决的是当控制一个对象状态的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类中,可以把复杂的判断逻辑简化。
状态模式的结构
状态模式中的角色:
- 上下文环境(Context):它定义了客户程序需要的接口并维护一个具体状态角色的实例,将与状态相关的操作委托给当前的Concrete State对象来处理。
由于环境类的状态存在多样性且在不同状态下对象的行为有所不同,因此将状态独立出去形成单独的状态类。在环境类中维护一个抽象状态类State的实例,这个实例定义当前状态,在具体实现时,它是一个State子类的对象。 - 抽象状态(State):定义一个接口以封装使用上下文环境的的一个特定状态相关的行为。在抽象状态类中声明了各种不同状态对应的方法,
而在其子类中实现了这些方法,由于不同状态下对象的行为可能不同,因此在不同子类中方法的实现可能存在不同,相同的方法可以写在抽象状态类中。 - 具体状态(Concrete State):实现抽象状态定义的接口。每一个子类实现一个与环境类的一个状态相关的行为,每一个具体状态类对应环境的一个具体状态,不同的具体状态类其行为有所不同。
使用场景:对象的行为依赖于它的某些属性值,状态的改变将导致行为的变化。在代码中包含大量与对象状态有关的条件语句,这些条件语句的出现,会导致代码的可维护性和灵活性变差,不能方便地增加和删除状态,并且导致客户类与类库之间的耦合增强。
状态模式的实现
下面的实例,演示获取顾客的折扣,顾客分为普通顾客和VIP顾客,对应不一样的折扣。
上下文环境
//定义当前的状态public class Context { private State state; public State getState() { return state; } public void setState(State state) { this.state = state; } public String stateMessage(){ return state.getState(); }}
状态
//定义和Context中的状态相对应的行为public interface State { //获取折扣 String getPriceState();}
具体状态
具体状态有两种:普通顾客和VIP客户。
class CommonConsumer implements State{ @Override public String getPriceState() { return "10%"; } }class VIPConsumer implements State{ @Override public String getPriceState() { return "20%"; } }
测试类
public class StateTest { public static void main(String args[]){ Context context=new Context(); context.setState(new CommonConsumer()); System.out.println("普通客户的折扣为: " + context.stateMessage()); context.setState(new VIPConsumer()); System.out.println("vip的折扣为: " + context.stateMessage()); }}
总结
状态模式封装了状态的转换规则,在状态模式中可以将状态的转换代码封装在环境类或者具体状态类中,可以对状态转换代码进行集中管理,而不是分散在一个个业务方法中。将所有与某个状态有关的行为放到一个类中,只需要注入一个不同的状态对象即可使环境对象拥有不同的行为。允许状态转换逻辑与状态对象合成一体,而不是提供一个巨大的条件语句块,状态模式可以让我们避免使用庞大的条件语句来将业务方法和状态转换代码交织在一起。
状态模式缺点:
- 状态模式的使用必然会增加系统中类和对象的个数,导致系统运行开销增大。
- 状态模式的结构与实现都较为复杂,如果使用不当将导致程序结构和代码的混乱,增加系统设计的难度。
- 状态模式对“开闭原则”的支持并不太好,增加新的状态类需要修改那些负责状态转换的源代码,否则无法转换到新增状态;而且修改某个状态类的行为也需修改对应类的源代码。
vs 策略模式
策略模式一般用于单个算法的替换,客户端事先必须知道所有的可替换策略,由客户端去指定环境类需要哪个策略,注意通常都只有一个最恰当的策略(算法)被选择。其他策略是同级的,可互相动态的在运行中替换原有策略。
状态模式的每个状态子类中需要包含环境类(Context)中的所有方法的具体实现——条件语句。通过把行为和行为对应的逻辑包装到状态类里,在环境类里消除大量的逻辑判断,而不同状态的切换由继承(实现)State的状态子类去实现,当发现修改的当前对象的状态不是自己这个状态所对应的参数,则各个状态子类自己给Context类切换状态(有职责链模式思想),且客户端不直接和状态类交互,客户端不需要了解状态!(和策略不一样),策略模式是直接依赖注入到Context类的参数进行选择策略,不存在切换状态的操作,客户端需要了解策略!
联系:状态模式和策略模式都是为具有多种可能情形设计的模式,把不同的处理情形抽象为一个相同的接口(抽象类),符合开闭原则,且策略模式更具有一般性。在实践中,可以用策略模式来封装几乎任何类型的规则,只要在分析过程中发现需要在不同实践应用不同的业务规则,就可以考虑使用策略模式处理,在这点上策略模式是包含状态模式的功能的。
参考
微信打赏
支付宝打赏
- 本文作者: aoho
- 本文链接: blueskykong.com/2017/03/18/…
- 版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 许可协议。转载请注明出处!