本帖最后由 犯困嫌疑人 于 2023-6-19 11:51 编辑
概述有限状态机是一种用来进行对象行为建模的工具,作用是描述对象在它的生命周期内所经历的状态序列,以及如何响应来自外界的各种事件。
介绍意图:将业务流程状态化,划分状态和相应的触发事件与动作,利用生命周期事件进行控制与执行。
主要解决:对象的行为依赖于它的状态(属性),并且可以根据它的状态改变而改变它的相关行为。
何时使用:代码中存在大量的if else来判断对象的状态时;一个对象的状态越多、发生的事件越多,就越适合采用有限状态机的写法
如何解决:将各种具体的状态抽象出来。
优点:有限状态机的写法,逻辑清晰,表达力强,有利于封装事件,实现后易于阅读和理解。
缺点:系统类和对象的个数增加;结构和实现都较为繁杂,使用不当会导致程序结构和代码混乱;对于新增的状态,往往需要修改负责状态转换的代码对"开闭原则"的支持不友好。
使用场景:1.行为随状态改变而改变的场景下;2.行为受到状态约束的时候;
特点:状态总数是有限的;任一时刻,只处在一种状态之中;某种条件下会转换状态。
简单实现:
/**
* 状态机
*/
class StateMachine {
/**当前状态 */
private _currentState: StateBase;
/**所有的状态 */
private _allStates: StateBase[] = [];
/**状态对象 */
private _actor: Transform;
constructor(actor: Transform) {
this._actor = actor;
//准备好所有的状态实例
this._allStates = [new BornState(this, actor), new MoveForwardState(this, actor), new RollForwardState(this, actor)]
this._currentState = this._allStates[0];
this._currentState.onEnter();
}
/**切换到另一个状态 */
public toState(name: string) {
if (this._currentState.constructor.name == name) return;
let nextState: StateBase = this._allStates.find(i => i.constructor.name == name);
this._currentState.onExit();
this._currentState = nextState;
this._currentState.onEnter();
}
/**帧驱动,也算是对外接受条件的一个接口 */
public update(dt: number) {
this._currentState.onUpdate(dt);
}
}
/**
* 状态基类
*/
class StateBase {
//归属于哪个状态机
protected _fsm: StateMachine;
protected _actor: Transform;
constructor(fsm: StateMachine, actor: Transform) {
this._fsm = fsm;
this._actor = actor;
}
/**进入状态 */
onEnter() { }
/**帧驱动 */
onUpdate(dt: number) { }
/**退出状态 */
onExit() { }
}
/**
* 向前行走
*/
class MoveForwardState extends StateBase {
private readonly speed: number = 1;
override onUpdate(dt: number): void {
this._actor.location.x += dt * this.speed;
}
}
/**
* 向前滚
*/
class RollForwardState extends StateBase {
private readonly moveSpeed: number = 1;
private readonly rollSpeed: number = 1;
override onUpdate(dt: number) {
this._actor.location.x += dt * this.moveSpeed;
this._actor.rotation.y += dt * this.rollSpeed;
}
}
/**
* 出生状态
*/
class BornState extends StateBase {
private readonly bornLocation: Vector = Vector.zero;
override onEnter(): void {
this._actor.location = this.bornLocation;
}
}
let fsm = new StateMachine(new Transform());
存在的问题:每次在实现状态机的时候我们都要去写一遍有限状态实例,当前状态,状态切换。
改造成泛型:
/**
* 泛型实现
*/
class StateMachine<A> {
/**当前状态 */
private _currentState: StateBase<A>;
/**所有的状态 */
private _allStates: StateBase<A>[] = [];
/**表现对象 */
private _actor: A;
constructor(actor: A, ...states: { new(fsm: StateMachine<A>, actor: A): StateBase<A> }[]) {
this._actor = actor;
//准备好所有的状态实例
for (let i of states) {
this._allStates.push(new i(this, this._actor));
}
this._currentState = this._allStates[0];
this._currentState.onEnter();
}
/**切换到另一个状态 */
public toState(state: new (target, machine) => StateBase<A>) {
if (this._currentState.constructor.name == state.name) return;
let nextState: StateBase<A> = this._allStates.find(i => i.constructor.name == state.name);
this._currentState.onExit();
this._currentState = nextState;
this._currentState.onEnter();
}
/**帧驱动,也算是对外接受条件的一个接口 */
public update(dt: number) {
this._currentState.onUpdate(dt);
}
}
/**
* 状态基类
*/
class StateBase<A> {
//归属于哪个状态机
protected _fsm: StateMachine<A>;
protected _actor: A;
constructor(fsm: StateMachine<A>, actor: A) {
this._fsm = fsm;
this._actor = actor;
}
/**进入状态 */
onEnter() { }
/**帧驱动 */
onUpdate(dt: number) { }
/**退出状态 */
onExit() { }
}
使用:
/**
* 向前行走
*/
class MoveForwardState extends StateBase<Transform> {
private readonly speed: number = 1;
override onUpdate(dt: number): void {
this._actor.location.x += dt * this.speed;
}
}
/**
* 向前滚
*/
class RollForwardState extends StateBase<Transform> {
private readonly moveSpeed: number = 1;
private readonly rollSpeed: number = 1;
override onUpdate(dt: number) {
this._actor.location.x += dt * this.moveSpeed;
this._actor.rotation.y += dt * this.rollSpeed;
}
}
/**
* 出生状态
*/
class BornState extends StateBase<Transform> {
private readonly bornLocation: Vector = Vector.zero;
override onEnter(): void {
this._actor.location = this.bornLocation;
}
}
let fsm = new StateMachine<Transform>(new Transform(), BornState, MoveForwardState, RollForwardState);
|