我只是想知道使用traits构建游戏对象在语义上是否正确。一方面,我将此视为具有关系(对象具有组件),但另一方面,我将组件视为组成对象。
例如。你有一个GameObject。 GameObject本身几乎没有任何作用,但是你混入它的东西给它带来了额外的属性。组件可以是HealthComponent(有健康),PhysicsComponent(模拟物理),ClickableComponent(可以点击)。
我喜欢使用traits的想法,因为所有属性和方法都添加到原始对象上,我可以player.getHP
而不是player.getHealthComponent.getHP
。另一方面,我发现使用特征的命名和语义很奇怪。 trait HealthComponent extends GameObject
- 这没有意义。 HealthComponent
属于GameObject,它不符合{em>是extend
隐含的关系。假设特征通常被视为其父类的专用版本,我是否正确?如果是这样,我将如何命名上述对象?
答案 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 ...
“假设特征通常被视为其父类的专用版本,我是否正确?” - 我不会这么说。如果你采用如上所述的自下而上的方法,你不会认为特质是某些父母的子类型,而是相反的方式(较大的组件由特征组成并由特征专门化)