Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 状态处理程序取决于状态模式中的具体上下文_C#_Oop_Design Patterns_State Pattern - Fatal编程技术网

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 = ????;
}