4

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

例如。你有一个游戏对象。一个游戏对象本身几乎什么都不做,但是你混入其中的东西赋予了它额外的属性。组件可以是 HealthComponent(有生命值)、PhysicsComponent(模拟物理)、ClickableComponent(可以点击)。

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

4

3 回答 3

4

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

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
于 2011-04-07T16:30:26.677 回答
3

如果您想限制您的 trait 可以混合的类型,您可以将依赖关系表示为自类型:

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

class Player extends GameObject with Movement with Health

这样,您的 trait 不会扩展GameObject,而只能用作GameObject.

另请参阅了解 Scala 的蛋糕模式和链接的文章。

于 2011-04-07T01:04:31.057 回答
3

trait HealthComponent扩展 GameObject - this doesn't make sense. AHealthComponent` 属于一个游戏对象”——你想要的是自我类型,并根据蛋糕模式构建:

所以你有了

trait HealthComponent {
   me: GameObject =>

   def inspect { me.querySomeGameObjectProperty }
}

val x = new GameObject with HealthComponent with ...

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

于 2011-04-07T01:12:20.693 回答