可以使用特征在Scala中构建游戏组件系统吗?

时间:2011-04-07 00:22:50

标签: scala traits

我只是想知道使用traits构建游戏对象在语义上是否正确。一方面,我将此视为具有关系(对象具有组件),但另一方面,我将组件视为组成对象。

例如。你有一个GameObject。 GameObject本身几乎没有任何作用,但是你混入它的东西给它带来了额外的属性。组件可以是HealthComponent(有健康),PhysicsComponent(模拟物理),ClickableComponent(可以点击)。

我喜欢使用traits的想法,因为所有属性和方法都添加到原始对象上,我可以player.getHP而不是player.getHealthComponent.getHP。另一方面,我发现使用特征的命名和语义很奇怪。 trait HealthComponent extends GameObject - 这没有意义。 HealthComponent属于GameObject,它不符合{em>是extend隐含的关系。假设特征通常被视为其父类的专用版本,我是否正确?如果是这样,我将如何命名上述对象?

3 个答案:

答案 0 :(得分:4)

为了补充@Moritz's answer,还可以在不从超类型继承实现的情况下堆叠相关行为:

trait HasFoo { def foo: Unit }

class GameObject extends HasFoo {
   def foo = {}
}

trait Health extends HasFoo { 
   self: GameObject =>

   abstract override def foo = {
      println("health foo")
      super.foo
   }
}

trait Dog extends HasFoo { 
   self: GameObject =>

   abstract override def foo = {
      println("dog foo")
      super.foo
   }
}

scala> val g = new GameObject with Health with Dog
g: GameObject with Health with Dog = $anon$1@33b7b32c

scala> g.foo
dog foo
health foo

答案 1 :(得分:3)

如果您想限制您的特质可以混合的类型,您可以将依赖关系表达为自我类型:

trait Health { self: GameObject =>
 // ...
}

class Player extends GameObject with Movement with Health

这样,您的特质不会延伸GameObject,但只能用作GameObject的子类型的混合物。

另请参阅Understanding Scala's Cake Pattern和链接文章。

答案 2 :(得分:3)

trait HealthComponent extends GameObject - this doesn't make sense. A HealthComponent`属于GameObject” - 你想要的是自我类型,并根据蛋糕模式构建< / EM>:

所以你有

trait HealthComponent {
   me: GameObject =>

   def inspect { me.querySomeGameObjectProperty }
}

val x = new GameObject with HealthComponent with ...

“假设特征通常被视为其父类的专用版本,我是否正确?” - 我不会这么说。如果你采用如上所述的自下而上的方法,你不会认为特质是某些父母的子类型,而是相反的方式(较大的组件由特征组成并由特征专门化)