我有一个源自BattleUnit
的基本上下文Unit
,它有两个州Idle
和Engaging
。并且这两个状态将引用BattleUnit
的实例来处理状态。从BattleUnit
我推导出一个Troop
,它可以移动,因此有另外两个状态Marching
和Chasing
。因此,如果我的State
被设计为:
public abstract class State {
protected Unit unit;
public abstract void Handle();
}
在Idle
和Engaging
状态下,我想处理BattleUnit
的实例。我可以攻击或只是闲着。但我需要操纵BattleUnit
的界面,Unit
可能不会退出Troop:BattleUnit
。同样,我想在Marching
或Chasing
中处理public class Engaging : State {
public void Handle() {
Troop trp = (Troop)unit;
// trp.troopMethod() which is not virtual
}
}
的实例。
那么我可以将单位投射到我期望的班级吗?即:
State
PS:我的Unit
中有一个public class Unit{
private State state;
//...
}
的实例,如:
{{1}}
有更好的方法吗?
答案 0 :(得分:1)
如何让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();
}
答案 1 :(得分:1)
您可以尝试的一种方法是让状态为特定类型的实体工作,例如操纵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
的类,其结构类似于上面列出的类,但基类为{{1} }。在State<Troop>
方法中,您将执行&#34; Marching&#34;和#34;追逐&#34; Handle
实例的逻辑。如果你后来决定你想要一个&#34;追逐&#34;对于车辆的状态,您可以创建以下内容:
Troop
然后,此类将接受构造函数中的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
方法将执行&#34;追逐&#34;车辆的逻辑。即使状态的目的相似,使不同实体具有不同状态的一个原因是允许您在您的州内实施特殊逻辑,例如:在这种情况下,&#34;追逐&#34; Handle
的逻辑检查是否存在雷达,但在&#34;追逐&#34;状态为Vehicle
你不想这样做(在这个例子中反正:))。
编辑1:
@zoujyjs ...在回答你的评论时,有两种方法可以解决这个问题:
第一种方法是创建一个Troop
接口,该接口将包含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>
类中删除泛型参数和Unit
属性,并且每个派生状态仍然会接受具体类型,即BattleUnit或Troop,而不是将其传递到基础State
类它将引用作为成员变量。因此,您的State
方法看起来像是:
Handle
您的public override void Handle()
{
_unit.X = ????;
_unit.Y = ????;
}
课程可以保留对Unit
的引用,您可以忽略对上述State
界面的需求。