概念
状态模式(State Pattern)是一种行为型设计模式,它允许对象在内部状态发生变化时改变其行为,使得对象看起来好像修改了其类
状态模式通常涉及三个核心角色:上下文(Context)、状态(State)和具体状态(Concrete State)
上下文(Context)
维护一个当前状态对象,并将状态相关的操作委托给当前状态对象处理
上下文对象通常会包含一个状态对象的引用,并提供方法来切换当前状态和执行状态相关的操作
状态(State)
定义了一个接口用于封装与上下文相关的行为
状态对象通常会包含多个方法,用于处理上下文对象的请求,并可能会改变上下文对象的状态
具体状态(Concrete 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 58 59 60 61 62 63
|
import VendingMachineState from './SubClass/VendingMachineState' import HasProductState from './SubClass/HasProductState' import SoldOutState from './SubClass/SoldOutState'
class VendingMachine {
constructor(initialStock) { this.hasProductState = new HasProductState(this) this.soldOutState = new SoldOutState(this) this.currentState = initialStock > 0 ? this.hasProductState : this.soldOutState }
setState(newState) { if (newState instanceof VendingMachineState) { console.log(`状态变化:从${this.currentState.constructor.name}到${newState.constructor.name}`) this.currentState = newState } else { console.error("无效的状态对象") } }
getHasProductState() { return this.hasProductState }
getSoldOutState() { return this.soldOutState }
sellProduct() { this.currentState.sellProduct() }
restock() { this.currentState.restock() } }
export default VendingMachine
|
状态基类
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
|
class VendingMachineState {
constructor(vendingMachine) { this.vendingMachine = vendingMachine; }
sellProduct() { throw new Error('子类必须实现此方法') }
restock() { throw new Error('子类必须实现此方法') } }
export default VendingMachineState
|
状态子类
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
|
import VendingMachineState from './VendingMachineState'
class HasProductState extends VendingMachineState {
sellProduct() { console.log("商品已售出") this.vendingMachine.setState(this.vendingMachine.getSoldOutState()) }
restock() { console.log("无法补货,售货机中已有商品") } }
export default HasProductState
import VendingMachineState from './VendingMachineState'
class SoldOutState extends VendingMachineState {
sellProduct() { console.log("无法售出,商品已售罄") }
restock() { console.log("补货成功") this.vendingMachine.setState(this.vendingMachine.getHasProductState()) } }
export default SoldOutState
|
怎么使用
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
|
import VendingMachine from '../StatePattern'
const vendingMachine = new VendingMachine(10)
vendingMachine.sellProduct() vendingMachine.restock()
vendingMachine.setState(vendingMachine.getSoldOutState()) vendingMachine.sellProduct() vendingMachine.restock()
vendingMachine.setState("InvalidState")
|
场景
自动售货机
自动售货机是一个很好的状态模式的应用示例
根据货物存量的不同,自动售货机的行为会发生变化,比如有货时可以售卖商品,缺货时需要进行补货等
订单状态管理
在电子商务系统中,订单状态经常会发生变化,比如订单创建、支付、发货、完成等
可以使用状态模式来管理订单的各种状态,使得订单对象能够根据不同状态执行不同的行为
文档编辑器
在文档编辑器中,可以根据文档的当前状态(比如编辑中、已保存、已发布等)来决定编辑器的行为,比如保存、发布、撤销等操作
多媒体播放器
在多媒体播放器中,播放器的行为会根据当前播放状态(比如播放、暂停、停止等)来改变,使用状态模式可以方便地管理播放器的状态转换
网络连接管理
在网络应用中,网络连接的状态经常会发生变化,比如连接中、已连接、断开连接等
状态模式可以用来管理网络连接的状态,以便根据不同的状态执行不同的操作
源代码