【问题标题】:Abstract factory with abstract parameters?具有抽象参数的抽象工厂?
【发布时间】:2011-09-08 15:04:12
【问题描述】:

我正在尝试使用抽象工厂(根据 http://www.dofactory.com/Patterns/PatternAbstract.aspx)设计一个良好的实体创建系统,但在涉及实例特定参数时我遇到了困难。

例如: 我有两个抽象工厂,一个用于创建射弹,一个用于创建板条箱

现在工厂可以是每种类型的一个实例,它从列表中传递一个抽象参数集(在基类中将共享材质、大小等),特定于类型的参数将是射弹的速度和板条箱的耐用性。

但我正在苦苦挣扎的是,最后当我有这个抽象工厂方法时,我用字符串“BulletProjectile”和“WeakCrate”等参数调用它,我需要提供实例特定的参数,更重要的是对于不同的工厂,它们具有不同的类型-对于射弹,它们将具有位置和速度,而板条箱将仅具有位置。 更糟糕的情况是用户或玩家正在创建一个箱子或类似的对象,并且能够定义其尺寸。我该如何处理?

【问题讨论】:

  • 当我在第二段中说任何一个时,我的第二个选择是为每种类型设置不同的工厂实例。 (子弹和手榴弹的 ProjectileFactory 实例
  • @Alas:你试过gamedev.stackexchange.com 吗?也许你有更多的运气,因为你特别要求游戏开发。
  • 这不是特定于游戏开发的问题,我只是想我会这样标记它,因为这就是我正在使用的示例。只是假装它们是网络表单而不是我正在创建的项目符号;)
  • @Alas:当然,只是认为它可能对您有更多帮助。 :)
  • 获得大量赞成票,因为这是一个棘手的问题:/我只是想不出解决方案

标签: c++ factory-pattern


【解决方案1】:

几个选项:

重新考虑您的使用情况

如果抽象工厂将工厂的用户与确切类型的生成方式分开,那么它是有用的。抽象工厂对其生产的内容没有任何限制,只是它是抽象的。它可以返回非抽象类型,或不在继承层次结构基础上的抽象类型。

如果使用工厂的代码已经可以获取不同的数据集来调用工厂,那么使用工厂的代码已经对从中产生的类型有所了解。

以下是一些可供考虑的选项:

  • 提供多种抽象工厂类型,每个Create方法,如GrenadeFactoryBulletFactory
  • 在单个抽象工厂类型上提供多个方法,例如CreateBulletCreateGrenade
  • 停止使用抽象工厂。如果您真的不需要抽象构造,而只需要抽象类型,这是一个不错的选择。

请记住,您仍然可以将派生类型 (Bullet) 传递给采用基类型(例如,EntityProjectile)的方法。

双发

如果您真的不喜欢将抽象工厂与抽象参数结合起来,那么您可能想要研究双重调度,或者Visitor Pattern。这里的关键是您试图让两个不同的虚拟方法相互组合,并基于这两个派生类型获得独特的行为组合。

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

它还需要大量额外的代码来实现访问者模式。

RTTI

你可以使用the C++ Run-Time Type Information feature

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

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

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

财物包

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

【讨论】:

  • 那你有什么建议?我确实需要一种为某些实体创建方法携带参数的好方法,但我也希望能够在关卡文件中序列化一组工厂参数。
  • @Alasdair:抽象工厂对于运行时解耦最有用,而不是真正用于序列化。通过对实时状态进行二进制序列化,您可能会获得更好的性能,当然您的数据不会独立于平台......
  • @Merylyn:不过,我想进行两次序列化。我已经在编辑器中创建了预定义的级别,然后首先加载,然后可以加载保存文件,该文件是一种状态,可以修改现有实体(可以移动它们,改变它们的健康或杀死它们) ,以及已生成的新实体。
  • @Alasdair:我了解一般要求,但我真的必须查看您的代码才能为您提供有关如何重构它的好建议。任何其他方式都是盲人带盲人:) 如果你想要具体的代码反馈,你可以试试codereview.stackexchange.com
  • @Merlyn:嗯,我还没有为此写任何东西,我一直在使用不同的实现,我刚刚得出的结论是我不喜欢
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多