前言
GOF设计模式分三大类:
- 创建型模式:关注对象的创建过程,包括单例模式、简单工厂模式、工厂方法模式、抽象工厂模式、原型模式和建造者模式。
- 结构型模式:关注类和对象之间的组合,包括适配器模式、桥接模式、组合模式、装饰模式、外观模式、享元模式和代理模式。
- 行为型模式:关注对象之间的交互,包括职责链模式、命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观察者模式、状态模式、策略模式、模板方法模式和访问者模式。
一、状态模式
状态模式(State Pattern)
定义:允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。其别名为状态对象(Objects for States)。
解决问题:如何设计和实现一个具有多个状态的对象?
使用场景:
- 对象的行为依赖于它的状态(例如某些属性值),状态的改变将导致行为的变化。
- 在代码中包含大量与对象状态有关的条件语句。
组成:
- Context(环境类):环境类又称为上下文类,它是拥有多种状态的对象。由于环境类的状态存在多样性且在不同状态下对象的行为有所不同,因此将状态独立出去形成单独的状态类。在环境类中维护一个抽象状态类State的实例,这个实例定义当前状态,在具体实现时,它是一个State子类的对象。
- State(抽象状态类):它用于定义一个接口以封装与环境类的一个特定状态相关的行为。在抽象状态类中声明各种不同状态对应的方法,而在其子类中实现这些方法。
- ConcreteState(具体状态类):它是抽象状态类的子类,每个子类实现一个与环境类的一个状态相关的行为。每个具体状态类对应环境类的一个具体状态,不同的具体状态类其行为有所不同。
补充说明:
- 在软件系统中,有些对象也像水一样具有多种状态,这些状态在某些情况下能够相互转换,而且对象在不同的状态下也将具有不同的行为。
- 状态模式,可使用UML状态图来表示。
- 状态模式用于解决系统中复杂对象的状态转换以及不同状态下行为的封装问题。
- 状态模式将一个对象的状态从该对象中分离出来,封装到专门的状态类中,使得对象状态可以灵活变化。
- 对于客户端而言,无须关心对象状态的转换以及对象所处的当前状态,无论对于何种状态的对象,客户端都可以一致性地处理。
- 在状态模式中引入了抽象状态类和具体状态类,它们是状态模式的核心。
- 在状态模式的使用过程中,一个对象的状态之间还可以进行相互转换。通常有以下两种实现状态转换的方式:
- 统一由环境类来负责状态之间的转换
- 由具体状态类来负责状态之间的转换
优点:
- 封装了状态的转换规则。
- 将所有与某个状态有关的行为放到一个类中,只需要注入一个不同的状态对象即可使环境对象拥有不同的行为。
- 允许状态转换逻辑与状态对象合成一体,而不是提供一个巨大的条件语句块。
- 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
缺点:
- 增加系统中类和对象的个数,导致系统运行开销增大。
- 程序结构与实现都较为复杂
- 状态模式对开闭原则的支持并不太好
二、状态模式示例
银行系统中的账户类设计
- 系统中账户存在3种状态,且在不同状态下账户存在不同的行为。
- NormalState表示正常状态,OverdraftState表示透支状态,RestrictedState表示受限状态。
- 如果账户中余额大于或等于0,则账户的状态为正常状态(Normal State),此时用户既可以向该账户存款也可以从该账户取款。
- 如果账户中余额小于0,并且大于-2000,则账户的状态为透支状态(Overdraft State),此时用户既可以向该账户存款也可以从该账户取款,但需要按天计算利息。
- 如果账户中余额小于等于-2000,那么账户的状态为受限状态(Restricted State),此时用户只能向该账户存款,不能再从中取款,同时也将按天计算利息。
"""状态模式"""
### 环境类
class Account:
"""银行账户"""
def __init__(self, owner: str, balance: float):
self.owner = owner # 开户名
self.balance = balance # 账户余额
self.state: AccountState = NormalState(self) # 设置初始状态
print(f"{self.owner} 开户,初始金额为 {self.balance}")
print("#" * 10)
def deposit(self, amount: float):
print(f"{self.owner} 存款 {amount}")
self.state.deposit(amount) # 调用状态对象方法
print(f"现在金额为 {self.balance}")
print(f"现在账户状态为 {type(self.state).__name__}")
print("#" * 10)
def withdraw(self, amount: float):
print(f"{self.owner} 取款 {amount}")
self.state.withdraw(amount) # 调用状态对象方法
print(f"现在金额为 {self.balance}")
print(f"现在账户状态为 {type(self.state).__name__}")
print("#" * 10)
def compute_interest(self):
self.state.compute_interest() # 调用状态对象方法
### 抽象状态类
class AccountState:
def __init__(self, acc: Account):
self.acc = acc
def deposit(self, amount: float):
raise NotImplementedError
def withdraw(self, amount: float):
raise NotImplementedError
def compute_interest(self):
raise NotImplementedError
def state_check(self):
raise NotImplementedError
### 具体状态类
class NormalState(AccountState):
"""正常状态"""
def deposit(self, amount):
self.acc.balance += amount
self.state_check()
def withdraw(self, amount):
self.acc.balance -= amount
self.state_check()
def compute_interest(self):
print("正常状态,无须支付利息!")
def state_check(self):
"""状态转换"""
if self.acc.balance > -2000 and self.acc.balance < 0:
self.acc.state = OverdraftState(self.acc)
elif self.acc.balance <= -2000:
self.acc.state = RestrictedState(self.acc)
class OverdraftState(AccountState):
"""透支状态"""
def deposit(self, amount):
self.acc.balance += amount
self.state_check()
def withdraw(self, amount):
self.acc.balance -= amount
self.state_check()
def compute_interest(self):
print("计算利息!")
def state_check(self):
if self.acc.balance >= 0:
self.acc.state = NormalState(self.acc)
elif self.acc.balance <= -2000:
self.acc.state = RestrictedState(self.acc)
class RestrictedState(AccountState):
"""受限状态"""
def deposit(self, amount):
self.acc.balance += amount
self.state_check()
def withdraw(self, amount):
print("账号受限,取款失败")
def compute_interest(self):
print("计算利息!")
def state_check(self):
if self.acc.balance > 0:
self.acc.state = NormalState(self.acc)
elif self.acc.balance > -2000:
self.acc.state = OverdraftState(self.acc)
- 客户端代码
if __name__ == "__main__":
acc = Account("张三", 0.0)
acc.deposit(1000)
acc.withdraw(2000)
acc.deposit(3000)
acc.withdraw(4000)
acc.withdraw(1000)
acc.compute_interest()
- 输出结果
张三 开户,初始金额为 0.0
##########
张三 存款 1000
现在金额为 1000.0
现在账户状态为 NormalState
##########
张三 取款 2000
现在金额为 -1000.0
现在账户状态为 OverdraftState
##########
张三 存款 3000
现在金额为 2000.0
现在账户状态为 NormalState
##########
张三 取款 4000
现在金额为 -2000.0
现在账户状态为 RestrictedState
##########
张三 取款 1000
账号受限,取款失败
现在金额为 -2000.0
现在账户状态为 RestrictedState
##########
计算利息!
您正在阅读的是《设计模式Python版》专栏!关注不迷路~