2011-04-07 36 views
4

我只是想知道,如果它是语义上正确的使用特质来建立游戏对象。一方面,我认为这是一个有一个关系(一个对象有组件),但另一方面,我将组件视为组成一个对象。可以使用特质在Scala中构建游戏组件系统吗?

例如。你有一个GameObject。游戏对象本身几乎没有任何东西,但是混入它的东西给了它更多的属性。组件可以是HealthComponent(有健康),PhysicsComponent(模拟物理),ClickableComponent(可以点击)。

我喜欢使用特征的想法,因为所有的属性和方法都添加在原始对象上,我可以做player.getHP而不是player.getHealthComponent.getHP。另一方面,我发现使用特征的命名和语义很奇怪。 trait HealthComponent extends GameObject - 这没有意义。 A HealthComponent属于游戏对象,它不符合关系,暗示了extend。我是否正确地认为特质通常被视为父类的专门版本?如果是这样,我会如何命名上述对象?

回答

3

如果你想限制你的特质可以在你混合的类型可以表达依赖作为自类型:

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

class Player extends GameObject with Movement with Health 

这样,你的特质并不延伸GameObject,但只能作为mixin为GameObject的亚型。请参阅Understanding Scala's Cake Pattern和链接的文章。

+0

这样更好,谢谢。但是,如果'Player'和'Movement'都定义了'foo'方法,那么我怎样才能让它被调用(像'super'那样工作? – ryeguy 2011-04-07 01:08:50

+2

你不能。您可以重写方法,但不能调用超类型的实现。如果你需要这样做,你必须使用继承。 – Moritz 2011-04-07 01:23:31

+2

您可以通过使用抽象覆盖来调用超类型的实现,而无需继承超类型。不过,你的特征必须从一个声明'foo'方法的公共接口继承。我将在一个答案中证明这一点。 – 2011-04-07 16:28:06

3

trait HealthComponent扩展游戏对象- this doesn't make sense. A HealthComponent`属于游戏物体” - 你想要的是根据蛋糕图案自我类型和建设:

所以你有

trait HealthComponent { 
    me: GameObject => 

    def inspect { me.querySomeGameObjectProperty } 
} 

val x = new GameObject with HealthComponent with ... 

“我是否正确地认为性状通常被视为他们父级的特殊版本?” - 我不会这么说。如果你采用自下而上的方法,你不会认为特征是某些父母的亚型,而是相反(更大的组成部分是由特质组成的并且由特性组成)

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 = [email protected] 

scala> g.foo 
dog foo 
health foo 
相关问题