Posts 设计模式-状态模式
Post
Cancel

设计模式-状态模式

概念解析

所谓 状态模式 :允许一个对象在其内部发生改变时改变其行为,使这个对象看上去就像改变了它的类型一样。其适用于的场景:

  1. 对象行为取决于其状态,且对象的状态是可变的
  2. 存在很多对象场景,本身都符合1. 场景,分散为很多多分支逻辑代码

状态模式的核心是设计:控制状态切换的上下文环境类,和描述状态的状态类(管理影响状态变化的各类信息)。其类图如下: img

Context 基类的核心操作做对状态进行转换, State 基类需要描述状态匹配的方法以及对象的行为。 状态模式 下需要注意的是:

  • 每个状态应当设计为 单例模式
  • 将所有和状态相关的行为放到单个类中(状态类),开发人员只需要关注对应类的逻辑开发即可
  • 允许状态转化逻辑和状态对象合并一起:通过特殊的状态对象实现

设计模板

状态模式 下的代码模板结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
from abc import ABCMeta, abstractmethod
# 引入ABCMeta/abstractmethod 定义抽象类和抽象方法

class Context(metaclass=ABCMeta):
    """状态模式的上下文环境"""

    def __init__(self):
        self.__states = []
        self.__curState = None
        # 判断state是否发生变化的依据,如果信息很多的话可以包装为类
        self.__stateInfo = None

    def addState(self, state):
        if (state not in self.__states):
            self.__states.append(state)

    def changeState(self, state):
        if (state is None):
            return False
        if (self.__curstate is None):
            print("初始化为:", state.getName())
        else:
            print("由", self.__curState.getName(), "变为", state.getName())
        self.__curState = state
        self.addState(state)
        return True

    def getState(self):
        return self.__curState

    def _setStateInfo(self, stateInfo):
        self.__stateInfo = stateInfo
        for state in self.__states:
            if (state.isMatch(stateInfo)):
                self.changeState(state)

    def _getStateInfo(self):
        return self.__stateInfo


class State:
    """状态基类"""

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


    def getName(self):
        return self.__name

    def isMatch(self, stateInfo):
        """关键方法:判断stateInfo是否符合当前状态范围"""
        return False

    @abstractmethod
    def behaviour(self, context):
        pass

实例分析

实例需求:实现“水”的三态变化,该对象能够根据温度变化进行状态变化,从而获得不同的行为。 对于上下文类(Water),需要实现的方法:

  • 初始化方法:初始化状态和温度
  • 温度切换:实现温度的上升/下降,同时切换状态
  • 行为表现:根据不同状态得到对应行为
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
class Water(Context):
    """水(H2O)"""

    def __init__(self):
        super().__init__()
        self.addState(SolidState("固态"))
        self.addState(LiquidState("液态"))
        self.addState(GaseousState("气态"))
        self.setTemperature(25)

    def getTemperature(self):
        return self._getStateInfo()

    def setTemperature(self, temperature):
        self._setStateInfo(temperature)

    def riseTemperature(self, step):
        self.setTemperature(self.getTemperature() + step)

    def reduceTemperature(self, step):
        self.setTemperature(self.getTemperature() - step)

    def behavior(self):
        state = self.getState()
        if(isinstance(state, State)):
            state.behavior(self)


# 单例的装饰器
def singleton(cls, *args, **kwargs):
    "构造一个单例的装饰器"
    instance = {}

    def __singleton(*args, **kwargs):
        if cls not in instance:
            instance[cls] = cls(*args, **kwargs)
        return instance[cls]

    return __singleton


@singleton
class SolidState(State):
    """固态"""

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

    def isMatch(self, stateInfo):
        return stateInfo < 0

    def behavior(self, context):
        print("我性格高冷,当前体温", context._getStateInfo(),
              "℃,我坚如钢铁,仿如一冷血动物,请用我砸人,嘿嘿……")


@singleton
class LiquidState(State):
    """液态"""

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

    def isMatch(self, stateInfo):
        return (stateInfo >= 0 and stateInfo < 100)

    def behavior(self, context):
        print("我性格温和,当前体温", context._getStateInfo(),
              "℃,我可滋润万物,饮用我可让你活力倍增……")

@singleton
class GaseousState(State):
    """气态"""

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

    def isMatch(self, stateInfo):
        return stateInfo >= 100

    def behavior(self, context):
        print("我性格热烈,当前体温", context._getStateInfo(),
              "℃,飞向天空是我毕生的梦想,在这你将看不到我的存在,我将达到无我的境界……")


# Test
########################################################################################################################
def testState():
    # water = Water(LiquidState("液态"))
    water = Water()
    water.behavior()
    water.setTemperature(-4)
    water.behavior()
    water.riseTemperature(18)
    water.behavior()
    water.riseTemperature(110)
    water.behavior()


testState()
This post is licensed under CC BY 4.0 by the author.

《流畅的Python》后记

设计模式-监听模式