尖刻版本:恭喜您重新发明了变量。糟糕。或者,充其量是接口上的属性。
有用的版本:
我可以看到您的设计存在一些问题。
第一个问题很简单复杂的。最好避免复杂化,除非你有令人信服的和existent其原因(即:不是“也许在未来”的需要)。否则YAGNI https://en.wikipedia.org/wiki/YAGNI。在求助于创建系统来在数据中表达这些概念之前,您应该始终尝试直接在代码中表达概念(就像我所说的重新发明变量;还可以考虑this https://en.wikipedia.org/wiki/Greenspuns_Tenth_Rule).
但我们假设您确实有充分的理由进行基于组件的设计......
第二个问题是boxing。装箱发生在您存储值类型的任何地方(例如:int
, float
, Vector2
, any struct
)直接作为引用类型(例如:object
, IEquatable
)。装箱对象是不可变的 - 因此每次您的位置发生变化时,都会创建一个新的装箱对象。装箱变量(相对)慢。装箱对象存储在堆上 - 因此它们在垃圾收集期间被考虑,并且可能导致垃圾收集。所以你在问题中提出的设计将会执行horribly.
我认为您对基于组件的设计的想法类似于这篇文章中解释的 https://cowboyprogramming.com/2007/01/05/evolve-your-heirachy/。这是一个有用的图表:
(source: cowboyprogramming.com http://cowboyprogramming.com/images/eyh/Fig-2.gif)
这让我想到了第三个问题:你不应该有多个组件占据一位置反正! (你好像要去way在设计中比您需要的更细化。)
基本上,基于组件的设计是关于重新发明class
,而不是variable. In a normal设计时,你可能有一个像这样的“渲染”功能:
public void Draw()
{
spriteBatch.Draw(texture, this.Position, Color.White);
}
但在基于组件的设计中,您将拥有Draw
and Position
in 不同的班级。顺便说一句,我会实现如下接口:
interface IRenderComponent { void Draw(); }
interface IPositionComponent { Vector2 Position { get; set; } }
那么如何Draw
access Position
?那么,你需要一种表达方式this
(如果你要重新发明类,this也许是您需要包含的最重要的概念)。
你会怎么做?这是给您的一个粗略的设计思路:
我会让每个组件类继承自Component
具有属性的类Self
。我会让Self
返回某种ComposedObject
具有通过接口访问构成组合对象的任何其他组件的机制。所以也许你的渲染组件可能看起来像:
class SimpleRenderer : Component, IRenderComponent
{
public void Draw()
{
sb.Draw(texture, Self.Get<IPositionComponent>().Position, Color.White);
}
}
(这与以下操作类似GameServiceContainer
(即:Game.Services
财产)。这里的想法是不ComposedObject
每个接口应该有多个实例。如果您的接口数量很少,ComposedObject
甚至不需要使用列表 - 只需直接存储每个列表即可。不过,您可以拥有实现多个接口的组件。)
现在,如果这对您来说太冗长,也许您可以添加一些方便的属性ComposedObject
(或使用扩展方法)对于常见的数据片段,例如Position
, 像这样:
public Vector2 Position { get { return Get<IPositionComponent>().Position; } }
那么你的绘制函数可以是这样的:
spriteBatch.Draw(texture, Self.Position, Color.White);