我正在尝试在 Unity 中制作一个可重用的状态机,据说可以处理常规状态和分层状态。
我有 3 个主要的抽象类,即 BaseState、StateMachine 和 StateFactory。
基础状态
public abstract class BaseState<EState>
where EState : Enum
{
protected StateFactory<EState, BaseState<EState>> _factory;
protected StateMachine<EState, BaseState<EState>> _machine;
protected EState _stateKey;
public BaseState(EState stateKey, StateMachine<EState, BaseState<EState>> machine, StateFactory<EState, BaseState<EState>> factory)
{
_stateKey = stateKey;
_machine = machine;
_factory = factory;
}
//Irrelevant logics
}
分层基础状态
public abstract class HBaseState<EState> : BaseState<EState> where EState : Enum
{
//whether this state is a primary state
protected bool _isRootState = false;
//references to the parent and child of this state;
protected HBaseState<EState> _parentState;
protected HBaseState<EState> _childState;
public HBaseState(EState stateKey, StateMachine<EState, HBaseState<EState>> machine, StateFactory<EState, HBaseState<EState>> factory, bool isRootState = false) : base(stateKey, *machine, factory*)
{
_stateKey = stateKey;
_isRootState = isRootState;
}
//Irrelevant logics
}
状态机
public abstract class StateMachine<EState, StateType> : MonoBehaviour
where EState : Enum
where StateType : BaseState<EState>
{
protected StateFactory<EState, StateType> _factory;
public StateType _currentState;
//Irrelevant logics
}
状态工厂
public abstract class StateFactory<EState, StateType> : MonoBehaviour
where EState : Enum
where StateType : BaseState<EState>
{
protected StateMachine<EState, StateType> _machine;
protected Dictionary<EState, StateType> _statesCached = new Dictionary<EState, StateType>();
public StateFactory(StateMachine<EState, StateType> machine, bool cacheStates = true)
{
_machine = machine;
InstantiateStates();
}
protected abstract void InstantiateStates();
//Irrelevant code
}
当我尝试为继承 BaseState 的分层状态类创建构造函数时,出现问题。
显然 C# 无法将
StateMachine<EState, HBaseState<EState>>
转换为 StateMachine<EState, BaseState<EState>>
(上面的代码示例),因此我无法将参数从 HBaseState 传递到其基本 BaseState 构造函数。尝试过打字,但也不起作用。
我对泛型的实现一开始就正确吗?如何重构我的代码以使其正常工作?
这是我第一次使用 StackOverflow,非常感谢您的帮助和建议:D
显然 C# 无法将 StateMachine
转换为 StateMachine
这是正确的,因为这是两种不同的类型,没有任何可能允许转换的方差。
在某些情况下,奇怪的重复模板模式可能会有所帮助。这可以帮助确保多个相关类型就
T
达成一致。即:
public abstract class Base<T> where T : Base<T>
{
public StateMachine<T> Machine;
}
public class Derived1 : Base<Derived1>
{
public void Test()
{
Derived1 current = base.Machine.CurrentState;
}
}
public class Derived2 : Base<Derived2>
{
public void Test()
{
Derived2 current = base.Machine.CurrentState;
}
}
public class StateMachine<T> where T : Base<T>
{
public T CurrentState { get; }
}
请注意,如果您想在同一状态机中使用多个不同的状态类型,这将无济于事。如果是这种情况,您需要使用普通的旧运行时多态性:
public abstract class Base
{
public StateMachine Machine;
}
public class Derived1 : Base
{ }
public class StateMachine : Base
{
public Base CurrentState { get; }
}
从经验来看,人们很容易将状态机之类的东西过度设计得过于通用和抽象。这通常会导致糟糕的结果,导致编译器错误,或者只是导致代码不可读。我的建议是从尽可能简单的开始,然后根据需要转向更复杂的模型。不要试图以可重用性的名义构建过于抽象和复杂的东西,因为复杂性可能会成为可重用性本身的障碍。