我有一个从Unit
派生的基本上下文BattleUnit
,它有两个状态Idle
和Engaging
。为了处理状态,这两个状态将有一个对BattleUnit
实例的引用。从BattleUnit
我派生了一个Troop
,它是可移动的,因此有两个额外的状态Marching
和Chasing
。所以如果我的State
被设计为:
public abstract class State {
protected Unit unit;
public abstract void Handle();
}
在Idle
和Engaging
状态下,我想处理BattleUnit
的实例。我可以进攻,也可以无所事事。但是我需要操作BattleUnit
的接口,Unit
可能没有退出。同样,我想在Marching
或Chasing
中处理Troop:BattleUnit
的实例。
那么我可以将Unit转换为我期望的类吗?即:
public class Engaging : State {
public void Handle() {
Troop trp = (Troop)unit;
// trp.troopMethod() which is not virtual
}
}
PS:我有一个State
的实例在我的Unit
像:
public class Unit{
private State state;
//...
}
有更好的方法吗?
您可以尝试的一种方法是让您的状态为特定类型的实体工作,例如操作BattleUnit
的状态和操作Troop
的状态。因此,例如,您可以从类似于
public abstract class State<T> where T : Unit
{
protected State(T unit)
{
this.Unit = unit;
}
protected T Unit { get; private set; }
public abstract void Handle();
}
然后为您创建Engaging
和Idle
状态BattleUnit
:
public class EngagingState : State<BattleUnit>
{
public EngagingState(BattleUnit unit)
: base(unit)
{
}
public override void Handle()
{
// Here you can implement the "engaging" logic for a BattleUnit.
this.Unit.X = ????;
this.Unit.Y = ????;
}
}
然后对Idle
状态执行相同的操作:
public class IdleState : State<BattleUnit>
{
...
}
这两种状态可以应用于任何从BattleUnit
派生的实例(假设BattleUnit
不是抽象的!)
对于您的Troop
类,您将创建两个名为MarchingState
和ChasingState
的类,结构将类似于上面概述的类,但基类将是State<Troop>
。在Handle
方法中,您将为Troop
实例执行"行进"one_answers"追逐"逻辑。现在,如果您稍后决定您想要车辆的"追逐"状态,那么您可以创建以下内容:
public class VehicleChasingState : State<Vehicle>
{
public VehicleChasingState(Vehicle unit)
: base(unit)
{
}
public override void Handle()
{
// Here you can implement the "chasing" logic for a Vehicle.
this.Unit.X = ????;
this.Unit.Y = ????;
if(this.Unit.HasRadar)
{
// Do special "chasing" logic when the vehicle has radar.
}
}
}
这个类将在构造函数中接受Vehicle
实例,Handle
方法将执行车辆的"追逐"逻辑。对于不同的实体有不同的状态的一个原因,即使状态的目的是相似的,是允许你在你的状态中实现特殊的逻辑,例如,在这种情况下,Vehicle
的"追逐"逻辑检查雷达的存在,但在Troop
的"追逐"状态下,你不会想要这样做(在这个例子中无论如何:))。
@zoujyjs……对于你的评论,有两种方法可以解决这个问题:
第一个是创建一个IState
接口,它将包含一个void Handle()
方法,并将由基本的State<T>
类实现。然后,您的Unit
类将具有protected IState CurrentState { get; set; }
属性。在某些时候,每个派生类都将为这个属性分配一个新的状态:
this.CurrentState = new EngagingState(this); // ...this is inside a BattleUnit instance
// or
this.CurrentState = new MarchingState(this); // ...this is inside a Troop instance
然后在某个时刻Unit
类会简单地调用this.CurrentState.Handle()
。没有泛型参数的IState
的主要意义在于,Unit
类不需要知道由状态管理的实例的类型。它所需要知道的是它必须调用Handle
方法。在State<T>
类上使用泛型参数的另一个好处是使实现逻辑更容易。
但是,泛型参数不是必需的,这就引出了第二个选项:
你可以从基础State
类中删除通用参数和Unit
属性,每个派生状态仍然会接受一个具体类型,即BattleUnit或Troop,但不是将其传递给基础State
类,而是将其作为成员变量保存引用。因此,您的Handle
方法看起来像:
public override void Handle()
{
_unit.X = ????;
_unit.Y = ????;
}
你的Unit
类可以保存对State
的引用,你可以忽略对上面提到的IState
接口的需要。
让State接受类型为Unit
的泛型参数如何?
public abstract class State<out T> where T : Unit
{
protected T unit;
public abstract void Handle();
}
public class Engaging : State<Troop> {
public void Handle() {
unit.troopMethod();
}