C# 状态处理程序取决于状态模式中的具体上下文
我有一个基本上下文C# 状态处理程序取决于状态模式中的具体上下文,c#,oop,design-patterns,state-pattern,C#,Oop,Design Patterns,State Pattern,我有一个基本上下文作战单元来自单元,它有两种状态空闲和交战。这两个状态将引用作战单元的实例来处理该状态。从BattleUnit我衍生出一支部队,它可以移动,因此有两种额外的状态行进和追逐。因此,如果我的状态设计为: public abstract class State { protected Unit unit; public abstract void Handle(); } 在空闲和接通状态下,我想处理作战单元的一个实例。我可以进攻,也可以无所事事。但是我需要操作作战单元
作战单元
来自单元
,它有两种状态空闲
和交战
。这两个状态将引用作战单元
的实例来处理该状态。从BattleUnit
我衍生出一支部队
,它可以移动,因此有两种额外的状态行进
和追逐
。因此,如果我的状态
设计为:
public abstract class State {
protected Unit unit;
public abstract void Handle();
}
在空闲
和接通
状态下,我想处理作战单元
的一个实例。我可以进攻,也可以无所事事。但是我需要操作作战单元
的界面,该界面可能不会在单元
中退出。同样地,我想在行进
或追逐
中处理部队:作战部队
的一个实例
那么我能把这个单元投给我期望的班级吗?i、 e:
public class Engaging : State {
public void Handle() {
Troop trp = (Troop)unit;
// trp.troopMethod() which is not virtual
}
}
PS:我的单元中有一个状态的实例,比如:
public class Unit{
private State state;
//...
}
有更好的方法吗?让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();
}
公共抽象类状态,其中T:Unit
{
受保护的T单元;
公共抽象无效句柄();
}
公共类:国家{
公共无效句柄(){
unit.troopMethod();
}
您可以尝试的一种方法是让您的状态为特定类型的实体工作,例如,操作作战单元的状态和操作部队的状态。因此,例如,您可以从类似以下的基本状态开始:
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();
}
然后对空闲状态执行相同操作:
public class IdleState : State<BattleUnit>
{
...
}
然后该类将接受构造函数中的Vehicle
实例,而Handle
方法将执行“追踪”车辆的逻辑。不同实体具有不同状态的一个原因是,即使状态的目的相似,也允许您在您的状态中实施特殊逻辑,例如,在这种情况下,车辆的“追踪”逻辑检查雷达的存在,但在“追踪”中声明一支部队
您不想这样做(在本例中:))
编辑1:
@zoujyjs…对于你的评论,有两种方法可以解决这个问题:
第一种方法是创建一个IState
接口,该接口将包含一个void Handle()
方法,并将由基本State
类实现。然后,您的单元
类将具有一个受保护的IState CurrentState{get;set;}
property。每个派生类在某个时候都会为此属性分配一个新状态:
this.CurrentState = new EngagingState(this); // ...this is inside a BattleUnit instance
// or
this.CurrentState = new MarchingState(this); // ...this is inside a Troop instance
然后在某个时刻,单元
类会简单地调用this.CurrentState.Handle()
。拥有一个没有通用参数的IState
的要点是单元
类不需要知道由状态管理的实例的类型。它需要知道的是它必须调用句柄
方法。在状态
类上拥有通用参数的额外好处是它更容易实现逻辑
但是,通用参数不是必需的,这导致我选择了第二个选项:
您可以从基本状态
类中删除泛型参数和单位
属性,每个派生状态仍将接受一个具体类型,即作战单位或部队,但它不会将其传递到基本状态
类,而是将引用作为成员变量。因此,您的句柄
方法看起来像:
public override void Handle()
{
_unit.X = ????;
_unit.Y = ????;
}
你的Unit
类可以保存对State
的引用,你可以忽略上面提到的IState
接口的需要。我认为这是行不通的。因为我在BattleUnit
中也有一个State
实例来指示当前状态,并且我有一个更改状态的规则。这使得每个状态都不是从一个公共根派生出来的,而是一个不同的根。我说的对吗?不对。单位仍然是所有状态的根,我没有更改继承层次结构。我的意思是,现在状态不再在同一层次结构中。我不能在单位中更改状态。为什么在状态
和单位
之间存在循环依赖关系?但它需要。显然实际上,Unit
需要维护当前的状态
并调用State.Handle()
根据该状态
做一些事情。当状态
处理问题时,它需要对Unit做一些事情,例如部队移动()
和BattleUnit
无法移动
。您真的需要在State类中引用该单元吗?如果从该单元调用Handle方法,它可以将自身作为参数传递给该方法。您仍然需要在Handle方法中将该单元强制转换为正确的类型。但此更改可能仍然会导致e设计稍微简单一点。是的,这是一个解决办法。我问过其他人,他们告诉我这基本上是一个双重分派问题。修改@YuvalItzchakov的解决方案会起作用。那就是保留抽象类状态,而模板则是具体状态。这样,我必须在单元
中保留对状态的引用,但是另一个状态
在部队
中,它将隐藏继承的单位状态。但是无论如何,如果我有更复杂的需求,这是一个好主意。我想我现在将使用cast作为解决方法。我在这里花了太多时间,最好先满足我的最后期限:)。@zoujyjs…我更新了我的答案,以考虑到你的需求评论。我知道你将采用“演员阵容”的方法,但答案可能对其他人有用。:)
this.CurrentState = new EngagingState(this); // ...this is inside a BattleUnit instance
// or
this.CurrentState = new MarchingState(this); // ...this is inside a Troop instance
public override void Handle()
{
_unit.X = ????;
_unit.Y = ????;
}