抽象工厂与抽象参数?

9
我正在尝试使用抽象工厂(如http://www.dofactory.com/Patterns/PatternAbstract.aspx)设计一个良好的实体创建系统,但在处理实例特定参数时遇到了困难。
例如: 我有两个抽象工厂,一个用于创建弹丸,另一个用于创建箱子。
现在,工厂可以是每种类型的一个实例,从列表中传递一个抽象参数集(在基类中为共享材料、大小等),类型特定参数将是弹丸的速度和箱子的耐久性。
但我遇到的问题是,在最后当我调用这个抽象工厂方法并以字符串“BulletProjectile”和“WeakCrate”作为参数时,我需要提供实例特定参数,更重要的是它们对于不同的工厂是不同类型的——对于弹丸它们将具有位置和速度,而对于箱子则只有位置。 更糟糕的情况是当用户或玩家创建箱子或类似物体,并能够定义其尺寸时,我该如何处理呢?

当我在第二段中说“either”时,我的第二个选择是为每种类型拥有一个不同的工厂实例。(对于子弹和手榴弹都有一个ProjectileFactory实例) - deek0146
@Alas:你试过访问http://gamedev.stackexchange.com/吗?也许你在那里更有好运,因为你特别询问游戏开发方面的问题。 - Xeo
2
这不是一个特定于游戏开发的问题,我只是觉得标签一下,因为这是我使用的示例。就当它们是网页表单而不是我正在创建的项目符号吧 ;) - deek0146
@Alas:当然,我只是觉得这可能会更有帮助。 :) - Xeo
因为这是一个棘手的问题,所以获得了大量的赞同票:/ 我就是想不出解决办法 - deek0146
显示剩余2条评论
1个回答

6
一些选项:
重新考虑你的用法
如果抽象工厂将工厂的用户与确切类型的生成方式分离,则它是有用的。抽象工厂对于其所产生的内容没有任何限制,只要它是抽象的即可。它可以返回非抽象类型或不在继承层次结构的最底层的抽象类型。
如果使用工厂的代码已经可以获得不同的数据集来调用工厂,则使用工厂的代码已经具有某种知识,了解从中出来的类型。
以下是一些可以考虑的选项:
提供多个抽象工厂类型,每个类型都有一个Create方法,例如GrenadeFactory和BulletFactory。
在单个抽象工厂类型上提供多个方法,例如CreateBullet和CreateGrenade。
停止使用抽象工厂。如果你真的不需要抽象构造,只需要抽象类型,这是一个很好的选择。
记住,您仍然可以将派生类型(例如Bullet)传递给接受基类型(如EntityProjectile)的方法。

双重分派

如果您确实坚决要将抽象工厂与抽象参数结合起来,则可能需要研究双重分派或访问者模式。关键在于,您正在尝试将两个不同的虚拟方法组合在一起,并根据这两个派生类型得到独特的行为组合。

这将要求您为参数创建基本和派生类型,因此您无法传递简单类型(如int、string等),必须创建从基本Parameters类型派生的自定义参数结构。

这还需要大量额外的代码来实现Visitor模式。

RTTI

您可以使用C++运行时类型信息功能

使用dynamic_cast,您可以将基本类型转换为派生类型。您可以在工厂实现中执行此操作,以将基本参数类型转换为特定参数类型。

像双重分派一样,这也需要您为参数创建类型层次结构,但需要更少的代码将它们组合在一起(不需要访问者模式)。

然而,此选项会将您的工厂实现与参数结构实现紧密耦合。

属性包

您还可以使用一个string -> some type字典(例如string -> boost::any)。 这称为属性包。 但是,它会失去大量的编译时类型安全性,因为您基本上是通过字符串值查找所有内容。 我真的不建议这样做。


那么你有什么建议呢?我确实需要一个好的方法来传递某些实体创建方法的参数,但我也希望能够将一组工厂参数序列化到一个级别文件中。 - deek0146
@Alasdair:抽象工厂最有用的是在运行时解耦,而不是用于序列化。通过对实时状态进行二进制序列化,您可能会获得更好的性能,但当然您的数据将不具备平台独立性... - Merlyn Morgan-Graham
@Merylyn:我想对序列化进行两次处理。我已经在编辑器中创建了预定义的级别,并且首先加载它,然后可以加载保存文件,该文件是一个状态,可以修改现有实体(可以移动它们,更改它们的健康状况或杀死它们),以及新生成的实体。 - deek0146
@Merlyn:啊好吧,我还没有为这个写任何东西,我一直在使用另一种实现方式,但我刚得出结论,我不喜欢它。 - deek0146
@Alasdair:联合应该比RTTI更快,实际上。我认为没有涉及任何运行时类型转换。 - Merlyn Morgan-Graham
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接