状态模式

对象行为型模式

模式动机

很多情况下,一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫做状态,这样的对象叫有状态的对象。当与外界交互时,内部状态可能变化,使得系统行为也随之变化。

在UML图中使用状态图来描述对象状态的改变。

应用

因此状态模式允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。

状态模式包括如下角色:

  • 环境类Context
  • 抽象状态类State
  • 具体状态类ConcreteState

模式分析

  • 状态模式描述了对象状态的变化以及对象如何在每一种状态下表现出不同的行为
  • 关键是引入了一个抽象类专门表示对象的状态,对象的每一种状态都继承该类,并在不同具体状态类中实现了对应的行为,包括状态间的转换

以一个酒店入住的例子进行演示:

重点理解环境类和抽象状态类的作用

  • 环境类就是拥有状态的对象,状态的表示就通过各个状态类来实现,因此环境类可以充当状态管理器

  • 抽象状态类既可以是抽象类也可以是接口,不同的具体状态类去继承/实现即可

  • 状态类的产生是因为环境类存在多个状态,并且:

    • 这些状态经常切换
    • 不同状态对象的行为不同

    因此可以将不同对象下的行为单独提取出来封装到对应的具体状态类中,使得环境类在其内部状态(具体状态类)发生变化时行为也发生变化,看起来就好像环境类被修改了,但实际上是因为状态的切换

实例:论坛用户等级

优点

  1. 封装了转换规则
  2. 枚举可能的状态
  3. 所有与某个状态有关的行为都放到了一个类(抽象状态类)中,一定程度上可以方便地增加新状态,只需要改变对象状态即可改变对象行为
  4. 状态转换逻辑与状态对象合成一体
  5. 可以多个环境类共享同一个具体状态类,减少系统中具体状态类实例的数量

缺点

  1. 状态类的存在必然会直接系统类和对象的数量
  2. 不支持开闭原则,每次增加新的状态都必然要修改已有的状态转换的代码,不然无法到达新状态;并且修改某个状态下的行为也需要修改对于具体状态类的代码

适用场合

  1. 对象的行为依赖于它的状态,可以根据状态改变而改变它的行为
  2. 源代码中包含大量与对象状态有关的条件语句,此时可以用状态模式来简化,提高可维护性和灵活性

在工作流(涉及大量状态的转移及不同状态下的不同行为)或游戏等场景下的软件中会广泛使用状态模式,甚至用于其核心功能的设计;目前主流的RPG游戏往往使用状态模式对游戏角色进行控制(角色升级往往意味着状态和行为的变化),同时游戏程序本身也可以使用状态模式控制,其开始、运行、结束等状态分别对应游戏系统不同的行为,可以通过对这些状态的控制来实现游戏系统行为的控制。

共享状态

有些情况下多个对象需要共享同一个状态,如果希望在系统中实现多个环境类实例共享一个或多个状态,那么这些状态对象在环境类中应当定义为环境类的静态成员对象

简单状态模式

指所有状态相互独立,状态之间无需进行转换的状态模式,上面大篇幅讲述的时可切换状态的状态模式

这种状态模式下,每个状态类只需要封装状态对应的行为即可,无需关心状态的切换,可以在客户端直接实例化状态类,然后设置到环境类中。

简单状态模式是符合开闭原则的,新增状态类不会对已有系统的具体状态类代码造成影响,甚至可以将具体状态类写到配置文件中。

(•‿•)