源码地址:https://github.com/weilanhanf/PythonDesignPatterns
说明:
在软件开发过程中,各种应用程序可能会根据不同的情况做出不同的处理。最直接的方案就是把所有的可能发生的情况都考虑到。然后使用条件语句对不同情况的作出判断并进行处理。但是假如状态比较复杂,就会出现多个判断语句,判断语句中又包含这各种操作,这显然是不受欢迎的。状态模式的出现就是为了解决这种问题。
状态模式用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题,将一个对象的状态从该对象中分离出来,封装到专门的状态类中,使得对象状态可以灵活变化。
状态模式:允许一个对象在其内部状态改变时改变它的行为,即不同的状态对应了不同的行为。对象看起来似乎修改了它的类。很多情况下,一个对象的行为取决于一个或者多个动态变化的属性。这样的属性叫做状态,这样的对象叫做有状态的对象。其状态是从事先定义好的一系列值中取出的。当一个这样的对象与外部事件产生互动时,其内部状态就会改变,从而使得系统的行为也随之改变。
对于客户端而言,无须关心对象状态的转换以及对象所处的当前状态,无论对于何种状态的对象,客户端都可以一致处理
状态模式的结构
状态模式包含以下3个角色: Context(环境类) State(抽象状态类) ConcreteState(具体状态类)
实例:
电梯在我们周边随处可见,电梯的控制逻辑中心是由电梯控制器实现的。电梯的控制逻辑,即使简单点设计,把状态分成开门状态,停止状态和运行状态,操作分成开门、关门、运行、停止,那流程也是很复杂的。首先,开门状态不能开门、运行、停止;停止状态不能关门,停止;运行状态不能开门、关门、运行。要用一个一个if…else…实现,首先代码混乱,不易维护;二是不易扩展。
但是可以看出的是,每个操作仅仅是一个操作,状态切换与操作是分离的,这也造成后来操作和状态“相互配合”的“手忙脚乱”。如果把状态抽象成一个类,每个状态为一个子类,每个状态实现什么操作,不实现什么操作,仅仅在这个类中具体实现就可以了。
#实现抽象的状态类 class LiftState: def open(self): pass def close(self): pass def run(self): pass def stop(self): pass #实现各个具体的状态类 class OpenState(LiftState): def open(self): print("OPEN:The door is opened...") return self def close(self): print("OPEN:The door start to close...") print("OPEN:The door is closed") return StopState() def run(self): print("OPEN:Run Forbidden.") return self def stop(self): print("OPEN:Stop Forbidden.") return self class RunState(LiftState): def open(self): print("RUN:Open Forbidden.") return self def close(self): print("RUN:Close Forbidden.") return self def run(self): print("RUN:The lift is running...") return self def stop(self): print("RUN:The lift start to stop...") print("RUN:The lift stopped...") return StopState() class StopState(LiftState): def open(self): print("STOP:The door is opening...") print("STOP:The door is opened...") return OpenState() def close(self): print("STOP:Close Forbidden") return self def run(self): print("STOP:The lift start to run...") return RunState() def stop(self): print("STOP:The lift is stopped.") return self #为在业务中调度状态转移,还需要将上下文进行记录,需要一个上下文的类 class Context: lift_state="" def getState(self): return self.lift_state def setState(self,lift_state): self.lift_state=lift_state def open(self): self.setState(self.lift_state.open()) def close(self): self.setState(self.lift_state.close()) def run(self): self.setState(self.lift_state.run()) def stop(self): self.setState(self.lift_state.stop()) #这样,在进行电梯的调度时,只需要调度Context就可以了。业务逻辑中如下 if __name__=="__main__": ctx = Context() ctx.setState(StopState()) ctx.open() ctx.run() ctx.close() ctx.run() ctx.stop()
打印结果:
STOP:The door is opening...
STOP:The door is opened...
OPEN:Run Forbidden.
OPEN:The door start to close...
OPEN:The door is closed
STOP:The lift start to run...
RUN:The lift start to stop...
RUN:The lift stopped...
模式优点
封装了状态的转换规则,可以对状态转换代码进行集中管理,而不是分散在一个个业务方法中 。将所有与某个状态有关的行为放到一个类中,只需要注入一个不同的状态对象即可使环境对象拥有不同的行为。 允许状态转换逻辑与状态对象合成一体,而不是提供一个巨大的条件语句块,可以避免使用庞大的条件语句来将业务方法和状态转换代码交织在一起。 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
模式缺点
会增加系统中类和对象的个数,导致系统运行开销增大。 结构与实现都较为复杂,如果使用不当将导致程序结构和代码混乱,增加系统设计的难度 。对开闭原则的支持并不太好,增加新的状态类需要修改负责状态转换的源代码,否则无法转换到新增状态;而且修改某个状态类的行为也需要修改对应类的源代码。
模式适用环境
对象的行为依赖于它的状态(例如某些属性值),状态的改变将导致行为的变化 。在代码中包含大量与对象状态有关的条件语句,这些条件语句的出现会导致代码的可维护性和灵活性变差,不能方便地增加和删除状态,并且导致客户类与类库之间的耦合增强