状态模式与有限状态机 (FSM) 概念相关,但是,每个状态都由实现公共状态特征的单独类型表示,而不是实现大量条件语句。
状态之间的转换取决于每种状态类型的特定 trait 实现。
Rust 中的状态模式在Rust Book中有详细描述: https://doc.rust-lang.org/book/ch17-03-oo-design-patterns.html
状态模式经常与命令模式 混合使用,因为一个命令执行以后,必然带来状态的改变,命令促使状态变化,状态变化也可以使用事件活动表达,一个命令下达被执行以后,发出领域事件 ,这是事件溯源 的原理,事件溯源是一种 备忘录模式,通过备忘录可以实现时光旅行,返回历史上任何一个状态。
状态模式有一个基本 trait State和方法可以进行状态转换play:stop
pub trait State { |
next并且prev不更改状态,在impl dyn State中无法覆盖的单独块中可默认实现:
impl dyn State { |
每个状态都是实现的类型trait State:
pub struct StoppedState; |
在这些实现状态再完成play动作,如PlayingState代码:
fn play(self: Box<Self>, player: &mut Player) -> Box<dyn State> { |
这里用特殊self: Box<Self>符号定义。
- 首先,self不是一个引用,这意味着该方法是一种 "一次性的",它消耗了self并交换到另一个返回Box<dyn State>的状态。
- 其次,该方法消耗的是Box<dyn State>这样的Box对象,而不是像PlayingState这样的具体类型的对象,因为具体状态在编译时是未知的。
最后,调用相同的操作play会根据调用的位置转换到不同的状态:
let state = Box::new(StoppedState); // StoppedState. |