Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
特征可以用于在Scala中构建游戏组件系统吗?_Scala_Traits - Fatal编程技术网

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

特征可以用于在Scala中构建游戏组件系统吗?,scala,traits,Scala,Traits,我只是想知道使用traits构建游戏对象在语义上是否正确。一方面,我将其视为具有关系(对象具有组件),但另一方面,我将组件视为构成对象 比如说。你有一个游戏对象。游戏对象本身几乎什么都不做,但你混入其中的东西赋予了它额外的属性。组件可以是HealthComponent(具有健康)、PhysicComponent(模拟物理)、ClickableComponent(可以单击) 我喜欢使用traits的想法,因为所有属性和方法都添加到原始对象上,我可以执行player.getHP而不是player.g

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

比如说。你有一个游戏对象。游戏对象本身几乎什么都不做,但你混入其中的东西赋予了它额外的属性。组件可以是HealthComponent(具有健康)、PhysicComponent(模拟物理)、ClickableComponent(可以单击)


我喜欢使用traits的想法,因为所有属性和方法都添加到原始对象上,我可以执行
player.getHP
而不是
player.getHealthComponent.getHP
。另一方面,我发现使用traits的命名和语义很奇怪<代码>特征健康组件扩展游戏对象-这没有意义。
HealthComponent
属于游戏对象,它不满足
extend
所暗示的关系。我假设特质通常被视为其父类的特殊版本,对吗?如果是这样,我将如何命名上述对象?

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

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

class Player extends GameObject with Movement with Health
这样你的特质就不会扩展到
GameObject
,而只能作为
GameObject
的子类型的混入

另请参阅和链接文章。

trait HealthComponent
扩展了游戏对象
-这没有意义。
HealthComponent`属于游戏对象”--您需要的是自我类型,并根据蛋糕模式进行构建:

你有吗

trait HealthComponent {
   me: GameObject =>

   def inspect { me.querySomeGameObjectProperty }
}

val x = new GameObject with HealthComponent with ...
“我假设特质通常被视为其父类的特殊版本,对吗?”——我不会这么说。如果您采用上述自底向上的方法,您不会认为trait是某些父类的子类型,相反(更大的组件由trait组成并由trait专门化)

作为补充,也可以在不继承超级类型实现的情况下堆叠相关行为:

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

那更好,谢谢。但是如果
Player
Movement
都定义了method
foo
,我怎么才能让它们都被调用(类似于
super
)呢?你不能。可以重写方法,但不能调用超级类型的实现。如果需要这样做,您必须使用继承。您可以调用超级类型的实现,而无需使用抽象重写从超级类型继承。但是,您的traits必须继承自声明
foo
方法的公共接口。我将在回答中演示这一点。