问题描述
这是我的用例。假设我有一款具有两种模式的游戏:CoolMode和NormalMode。
两种游戏模式都非常不同,但是共有三个共同的对象:输入,得分和裁判。每种模式都有不同的实现方式,但是可以使用相同的代码从主游戏中调用。
interface Judger{
Score Judge(Input i);
}
abstract class Score {...}
abstract class Input {...}
例如,我想确保CoolMode输入不会传递给NormalMode裁判。所以我的第一个解决方案是:
interface GameMode{}
interface Judger<T> where T:GameMode{
Score<T> Judge(Input<T> i);
}
abstract class Score<T> where T:GameMode {...}
abstract class Input<T> where T:GameMode {...}
interface NormalMode{}
class NormalJudger:Judger<NormalMode>{
Score<NormalMode> Judge(Input<NormalMode> i);
}
class NormalScore:Score<NormalMode>{...}
class NormalInput:NormalInput<NormalMode>{...}
...
问题在于现在NormalJudger可以接受任何输入,而不仅仅是NormalInput。
如何强制(在编译时)类{NormalJudger,NormalScore,NormalInput}相互使用?
解决方法
问题在于现在NormalJudger可以接受任何输入,而不仅仅是NormalInput。
如果这样意味着您可以让某人创建自己的Input<NormalMode>
实现并将其传递给NormalJudger
,那么实际上,您应该设计NormalJudger
以便它可以判断任何一种Input<NormalMode>
。这不是为什么您将Input
创建为抽象类吗?这是抽象的全部要点。 Judge
不必关心Input
是什么特定类型,只要它是Input<NormalMode>
。看来NormalMode
类型只是类型系统的“标记”,用来区分您的类型。好吧,如何使它实际上包含一些数据/逻辑,并使Judge
对其进行操作?
或者,您可以快速而又肮脏地使用Judge
类型,以不同的方式进行参数化。除了在模式上参数化外,在Score
和Input
上参数化:
public interface Judger<TScore,TInput>
where TScore: Score
where TInput: Input{
TScore Judge(TInput i);
}
public abstract class Score {}
public abstract class Input {}
interface NormalMode : GameMode {}
class NormalJudger:Judger<NormalScore,NormalInput>{
public NormalScore Judge(NormalInput i) {return null;}
}
class NormalScore:Score{}
class NormalInput:Input{}