警告:本题以 RPG 类比为例。
假设我正在使用 C# 制作我梦寐以求的 RPG。当玩家进入战斗时,会出现某种战场,其中包含与战斗相关的每个元素的引用,例如战场上的各种对手和可用物品。
现在所有这些元素都有一个但几个角色:例如,盟友(通过直接继承而成为战士)能够在战场上移动、发出命令或成为敌人的目标。
现在,石中的大剑在战斗中也有一些作用。显然它不能移动也不能发出命令,但它仍然可以成为目标,并且它可以(希望)被提升或使用。
在我的代码中,所有这些行为都由接口表示,因此无论实现它的对象如何,都可以使用具有相同行为的所有对象。
代码示例:
public class Ally : Fighter, IMovable, IActor, ITarget
{
// IMovable implementation
public void Move(...) { ... }
// IActor implementation
public bool HasInitiative { get { ... } }
public ICommand IssueCommand(...) { ... }
// ITarget implementation
public void OnTarget(...) { ... }
// other code ...
}
public class MightySword : ITarget, ILiftable, IUsable
{
// ITarget implementation
public void OnTarget(...) { ... }
// ... other interface implementation
// other code ...
}
现在我的问题是:我的 Battlefield 类应该如何保存对所有这些对象的引用?我提出了两种可能的解决方案,但目前尚不清楚哪一种是最好的,以及是否会找到更好的解决方案。
解决方案 A:
多次引用,直接访问:使用此解决方案,每个对象在其实现的每个接口中都被引用一次,因此我的战场类如下所示:
public class Battlefield : ...
{
IList<IMovable> movables;
IList<ITarget> targets;
IList<IActor> actors;
// ... and so on
}
Battlefield.Update 方法可能是这样的:
Update(...)
{
// Say every actor needs to target somebody else
// it has nothing to do in the Update method,
// but this is an example
foreach (IActor actor in actors)
{
if (actor.HasInitiative)
{
ITarget target = targets[actor.TargetIndex];
target.OnTarget(actor.IssueCommand(...));
}
}
}
该解决方案允许我们直接访问对象的各种行为,但它引入了冗余,因为必须将 Ally 引用到可移动对象、目标和参与者中。这种冗余意味着更大的内存占用,并且会使在战场上添加和删除对象变得更加复杂(现在每种类型都应该从哪些集合中添加/删除它)。
另外,添加一个新的接口意味着添加一个新的集合来保存项目并管理相应的代码。
解决方案 B:
引用一次,过滤访问:使用此解决方案,所有对象都派生自一个类或接口(类似于 IBattleElement),并存储在一个集合中。使用元素时,会根据它们的类型进行过滤:
Update(...)
{
IList<IActor> actors = elements.OfType<Actor>();
foreach (IActor actor in actors)
{
ITarget target = elements.OfType<Target>()[actor.TargetIndex];
target.OnTarget(actor.IssueCommand(...));
}
}
那里。没有更多的冗余,但我不喜欢使用“typeof”结构,我通常会尽量避免它。显然,这对于运行时性能来说更糟。
我在我的玩具项目中实施了解决方案 A,但在这个项目中没有什么对性能至关重要。答案不仅应该考虑性能(内存方面和 CPU 方面),还应该考虑为我或我的设计师可能必须执行的操作提供最佳设计,例如添加新的 BattleElement 类或新行为的新接口,添加并从战场中移除对象的实例,并且更普遍地在游戏逻辑中使用它们。
我为我的示例的一般愚蠢表示歉意,我希望我的英语足够好,并且我的问题至少引起了一点兴趣,并且并不表明设计本身的整体愚蠢。