2010-08-01 51 views
6

我目前正在發現scala,我在想是否可以在工廠使用特徵。使用工廠特徵

我嘗試這樣做:

 
abstract class Foo { 
    ... 
} 
object Foo { 
    def apply() = new Bar 

    private class Bar extends Foo { 
    ... 
    } 
} 

Foo() with MyTrait // Not working 

我想這是因爲with必須new之前。

那麼有沒有辦法做到這一點?

謝謝

+0

可能的重複[如何在scala中的泛型方法中創建特徵實例?](http://stackoverflow.com/questions/3274279/how-do-i-create-an-instance在一個通用的方法在斯卡拉) – 2010-08-01 15:42:33

回答

4

不,它太晚了,apply()方法返回時已創建實例。

你可以做的是使用工廠方法內的特質。下面的代碼是從相當大的代碼示例我寫:

object Avatar { 
// Avatar factory method 
def apply(name: String, race: RaceType.Value, character: CharacterType.Value 
): Avatar = { 
    race match { 
     case RaceType.Dwarf => { 
     character match { 
      case CharacterType.Thief => new Avatar(name) with Dwarf with Thief 
      case CharacterType.Warrior => new Avatar(name) with Dwarf with Warrior 
      case CharacterType.Wizard => new Avatar(name) with Dwarf with Wizard 
     } 
     } 
     case RaceType.Elf => { 
     character match { 
      case CharacterType.Thief => new Avatar(name) with Elf with Thief 
      case CharacterType.Warrior => new Avatar(name) with Elf with Warrior 
      case CharacterType.Wizard => new Avatar(name) with Elf with Wizard 
     } 
     } 
    } 
    } 
} 

class Avatar(val name: String) extends Character { 
    ... 
} 

在這段代碼中自己的頭像的類型(職業和種族)在基礎上,RaceType和CharacterType枚舉工廠決定。你有什麼是一個工廠爲各種不同類型或類型的組合。

+1

在你的情況下,我們必須提前知道我們可以使用的不同特徵。但是如果我們不這樣做,是否有可能通過'def apply [T]()= new Foo with T'的概念中的定義將這些特性轉化爲工廠方法? – 2010-08-01 11:59:25

+2

@Mr_Qqn:不,你不能通過傳遞清單來做到這一點。如果您需要這種行爲,可以創建代理將代表特定特徵代入工廠創建的對象,併爲創建必要代理的特徵創建(隱式)轉換。 – 2010-08-01 15:39:32

+1

謝謝,它與代理完美配合。但是,通過創建隱式轉換,你的意思是什麼?一個'帶MyTrait的新FooProxy'可以正確完成這項工作。 – 2010-08-01 17:23:31

3

假設你有:

class Foo 
object Foo { def apply() = new Foo } 
trait Baz 

然後:

Foo() with Baz 

就類似於:

val foo = new Foo 
foo with Baz 

這將意味着某種形式的基於原型的繼承,這斯卡拉沒有按沒有。 (據我所知。)

(我猜想在思考錯誤是直接誤認爲=符號爲「替代符號」。即因爲Foo()意味着Foo.apply()和哪個「等於」新富,你可以用新富substitue富()。很明顯,你可以沒有哪個)

3

解決方案與隱式轉換

肯建議,代理可以幫助我們在這種情況下。我們在這裏試圖做的是在實例創建之後添加一個特徵。如果其他人編寫了該類(和apply()方法),並且無法訪問源,則此「猴子修補」可能很有用。在這種情況下,你所能做的就是增加對隱式轉換實例頂部的代理/包裝(無需手動轉換):


使用Foo例子中,我們可以做到這一點是這樣的:

class Foo 
object Foo { def apply() = new Foo } 
trait Baz { def usefulMethod(s: String) = "I am really useful, "+ s } 

// ---- Proxy/Wrapper ---- 
class FooWithBazProxy extends Foo with Baz 

// --- Implicit conversion --- 
implicit def foo2FooWithBazProxy(foo: Foo): FooWithBazProxy = new FooWithBazProxy 

// --- Dummy testcode --- 
val foo = Foo() 
println(foo.usefulMethod("not!")) 

輸出:

I am really useful, not! 

我不喜歡這個例子的原因是:

Baz不以任何方式使用Foo。很難看到我們爲什麼要附上usefulMethod()Foo的原因。


所以我做了其中的特點,我們「猴子補丁」到實例實際使用的情況下一個新的例子:

// --------- Predefined types ----------- 
trait Race { 
    def getName: String 
} 

class Avatar(val name: String) extends Race{ 
    override def getName = name 
} 

object Avatar{ 
    def apply() = new Avatar("Xerxes") 
} 

// ---------- Your new trait ----------- 
trait Elf extends Race { 
    def whoAmI = "I am "+ getName + ", the Elf. " 
} 

// ---- Proxy/Wrapper ---- 
class AvatarElfProxy(override val name: String) extends Avatar(name) with Elf 

// ---- Implicit conversion ---- 
implicit def avatar2AvatarElfProxy(Avatar: Avatar): AvatarElfProxy = new AvatarElfProxy(Avatar.name) 


// --- Dummy testcode --- 
val xerxes= Avatar() 
println(xerxes.whoAmI) 

打印:

I am Xerxes, the Elf. 

在這個例子中添加的Elf特徵使用它擴展的實例的getName方法。

如果您發現任何錯誤,我將不勝感激(尚)。

+0

我擴展了您的解決方案以啓用代碼,如'val xerxes = Avatar [Elf](「Xerxes」)' – 2010-08-03 16:49:07

2

與代理和隱式轉換

解此示例擴展歐萊的溶液,以允許用戶調用apply()方法(例如val xerxes = Avatar[Elf]("Xerxes"))時指定混入性狀。

// ----- Predefined types ----- 

trait Race { 
    def whoAmI: String 
} 

class Avatar[R <: Race](val name: String) 

object Avatar { 
    def apply[R <: Race](name: String) = new Avatar[R](name) 
} 

// ----- Generic proxy ----- 
class AvatarProxy[R <: Race](val avatar: Avatar[R]) 

implicit def proxy2Avatar[R <: Race](proxy: AvatarProxy[R]): Avatar[R] = 
     proxy.avatar 

// ----- A new trait ----- 
trait Elf extends Race { 
    self: AvatarProxy[Elf] => 
    def whoAmI = "I am " + self.name + ", the Elf." 
} 

implicit def avatar2Elf(avatar: Avatar[Elf]): AvatarProxy[Elf] with Elf = 
     new AvatarProxy[Elf](avatar) with Elf 

// --- Test code ----- 
val xerxes = Avatar[Elf]("Xerxes") 
println(xerxes.whoAmI) 

打印:

我是薛西斯的精靈。