2011-04-07 49 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 
相關問題