python 实现 状态模式

本文的目录地址

本文的代码地址

面向对象编程着力于在对象交互时改变它们的状态。在很多问题中,有限状态机(通常名为状态机)是一个非常方便的状态转换建模(并在必要时以数学方式形式化)工具。首先,什么是状态机?状态机是一个抽象机器,有两个关键部分,状态和转换。状态是指系统的当前(激活)状况。例如,假设我们有一个收音机,其两个可能的状态是在调频波段(FM)或调幅波段(AM)上调节。另一个可能的状态是从一个FM/AM无线电台切换到另一个。转换是指从一个状态切换到另一个状态,因某个事件或条件的触发而开始。通常,在一次转换发生之前或之后会执行一个或一组动作。假设我们的收音机被调到107 FM无线电台,一次状态转换的例子是收听人按下按钮切换到107.5 FM。
状态机的一个不错的特性是可以用图来表现(称为状态图),其中每个状态都是一个节点,每个转换都是两个节点之间的边。下图展示了一个典型操作系统进程的状态图(不是针对特定的系统),经Wikipedia允许使用。进程一开始由用户创建好,就进入“已创建/新建”状态。这个状态只能切换到“等待”状态,这个状态转换发生在调度器将进程加载进内存并添加到“等待/预备执行”的进程队列之时。一个“等待”进程有两个可能的状态转换:可被选择而执行(切换到“运行”状态),或被更高优先级的进程所替代(切换到“换
出并等待”状态)。
进程的其他典型状态还包括“终止”(已完成或已终止)、“阻塞”(例如,等待一个I/O操作完成)等。需要注意,一个状态机在一个特定时间点只能有一个激活状态。例如,一个进程不可能同时处于“已创建”状态和“运行”状态。

python 实现 状态模式_第1张图片

状态机可用于解决多种不同的问题,包括非计算机的问题。非计算机的例子包括自动售货机、电梯、交通灯、暗码锁、停车计时器、自动加油泵及自然语言文法描述。计算机方面的例子包括游戏编程和计算机编程的其他领域、硬件设计、协议设计,以及编程语言解析。

好了,听起来很美好。但是状态机如何关联到状态设计模式(State design pattern)呢?其实状态模式就是应用到一个特定软件工程问题的状态机。

这里引用Thomas Jaeger说过的一句话:“状态设计模式解决的是一定上下文中无限数量状态的完全封装,从而实现更好的可维护性和灵活性。”

举例代码实现

下面我们将实现一个具备上图操作系统状态及其状态转换的状态机。这里用了第三方的python模块state_machine。没有安装的可以使用pip安装一下

python 实现 状态模式_第2张图片

使用state_machine模块创建状态机的第一个步骤是使用@acts_as_state_machine修饰器。

下一步,使用State定义状态机的状态,初始状态可以参数inital=True指定。

接着使用Event定义状态转换。参数from_states和to_state来定义一个可能的转换。from_states可以是单个状态或一组状态(元组)。

在发生状态转换时,如果什么影响都没有,那转换就没什么用了。state_machine模块提供@before和@after修饰器,用于在状态转换之前或之后执行动作。

transition()函数接受三个参数:process、event和event_name。process是一个Process类实例,event是一个Event类(wait、run和terminate等)实例,而event_name是事件的名称。在尝试执行event时,如果发生错误,则会输出事件的名称。

state_info()函数展示进程当前(激活)状态的一些基本信息。

完整代码文件state.py

from state_machine import State, Event, acts_as_state_machine, after, before, InvalidStateTransition


@acts_as_state_machine
class Process:
    created = State(initial=True)
    waiting = State()
    running = State()
    terminated = State()
    blocked = State()
    swapped_out_waiting = State()
    swapped_out_blocked = State()

    wait = Event(from_states=(created, running, blocked, swapped_out_waiting), to_state=waiting)
    run = Event(from_states=waiting, to_state=running)
    terminate = Event(from_states=running, to_state=terminated)
    block = Event(from_states=(running, swapped_out_blocked), to_state=blocked)
    swap_block = Event(from_states=blocked, to_state=swapped_out_blocked)

    def __init__(self, name):
        self.name = name

    @after('wait')
    def wait_info(self):
        print('{} entered waiting mode'.format(self.name))

    @after('run')
    def run_info(self):
        print('{} is running'.format(self.name))

    @before('terminate')
    def terminate_info(self):
        print('{} terminated'.format(self.name))

    @after('block')
    def block_info(self):
        print('{} is blocked'.format(self.name))

    @after('swap_wait')
    def swap_wait_info(self):
        print('{} is swapped out and waiting'.format(self.name))

    @after('swap_block')
    def swap_block_info(self):
        print('{} is swapped out and blocked'.format(self.name))


def transition(process, event, event_name):
    try:
        event()
    except InvalidStateTransition as err:
        print("Error: transition of {} from {} to {} failed".format(process.name,
                                                                    process.current_state, event_name))


def state_info(process):
    print('state of {}: {}'.format(process.name, process.current_state))


def main():
    RUNNING = 'running'
    WAITING = 'waiting'
    BLOCKED = 'blocked'
    TERMINATED = 'terminated'

    p1, p2 = Process('process1'), Process('process2')
    [state_info(p) for p in (p1, p2)]

    print()
    transition(p1, p1.wait, WAITING)
    transition(p2, p2.terminate, TERMINATED)
    [state_info(p) for p in (p1, p2)]

    print()
    transition(p1, p1.run, RUNNING)
    transition(p2, p2.wait, WAITING)
    [state_info(p) for p in (p1, p2)]

    print()
    transition(p2, p2.run, RUNNING)
    [state_info(p) for p in (p1, p2)]

    print()
    [transition(p, p.block, BLOCKED) for p in (p1, p2)]
    [state_info(p) for p in (p1, p2)]

    print()
    [transition(p, p.terminate, TERMINATED) for p in (p1, p2)]
    [state_info(p) for p in (p1, p2)]


if __name__ == '__main__':
    main()

输出结果如下:

state of process1: created
state of process2: created

process1 entered waiting mode
Error: transition of process2 from created to terminated failed
state of process1: waiting
state of process2: created

process1 is running
process2 entered waiting mode
state of process1: running
state of process2: waiting

process2 is running
state of process1: running
state of process2: running

process1 is blocked
process2 is blocked
state of process1: blocked
state of process2: blocked

Error: transition of process1 from blocked to terminated failed
Error: transition of process2 from blocked to terminated failed
state of process1: blocked
state of process2: blocked

Process finished with exit code 0

 

你可能感兴趣的:(设计模式,Python基础)