2013-12-12 80 views
6

讓我們假設我們有一個特質T。什麼是實現最好的辦法如下:在斯卡拉強制實施工廠的簡明方法

  • 大家誰寫的T的實現應該被強迫提供一種可能性,即允許T無參數初始化,即,我們可能不得不強制執行一個可配置的工廠。
  • 所有邏輯/數據僅取決於實際的初始化參數(某個實施AT)應集中處理/存儲,但應在工廠和A中提供。

最簡單的/簡潔的方式我認爲實現這一目標(大約)將添加一個特質的一家工廠,並鏈接T此工廠:

trait T { 
    val factory: TFactory 
} 
trait TFactory { 
    def build(): T 
    val description: String // example for logic/data that only depend on the parameters 
} 

// example implementation: 
class A(val factory: AFactory, paramA: Int, paramB: Int, paramC: Int) extends T 

class AFactory(paramA: Int, paramB: Int, paramC: Int) extends TFactory { 
    def build = new A(this, paramA, paramB, paramC) 
    val description = f"$paramA $paramB $paramC" 
} 

顯然,這並沒有真正「強制執行「工廠的實施(只要有替代實施可用),顯然可以生成A的實例,其鏈接到」錯誤的「TFactory。我也不喜歡這種方法是重複初始化參數。我經常創建另一個類AParams,它再次包裝所有參數(例如,以便於添加新參數)。因此,我最終得到了三個類,對於這個簡單的問題,imho是很多樣板。

我的問題是,是否有(可能完全)不同的方法,實現相同的主要目標,但更簡潔?

回答

1

我不太清楚我是否完全符合您的要求,但您對這種行爲有何看法?

trait TFactory{ 
    def build():T 
    val description:String 
} 

trait T extends TFactory 

//can't declare A without build and not make it abstract 
class A(paramA: Int, paramB: Int, paramC: Int) extends T { 
    def build = new A(paramA, paramB, paramC) 
    val description = f"$paramA $paramB $paramC"  
} 

val a1 = new A(1, 4, 5) 
val a2 = a1.build() 

//We can give ourselves as a factory to something that expects TFactory 
val factory:TFactory = a1 
val a_new = factory.build() 

//More likely we can just give our build method 
def func(f:()=>T) = { 
    val new_t = f() 
    new_t 
} 
val a_newer = func(a1.build) 


println(a1 +": " + a1.description) 
println(a2 +": " + a2.description) 
println(a_new +": " + a_new.description) 
println(a_newer +": " + a_newer.description) 

輸出:

[email protected]: 1 4 5 
[email protected]: 1 4 5 
[email protected]: 1 4 5 
[email protected]: 1 4 5 
+0

肯定是一個有趣的想法,謝謝!我看到的一個實際問題是,直覺上我會失去一個工廠輕量級的概念,而'T'的實際實現可能相當重量級。經常在我的用例中構造一個真正的'A'會涉及大量的初始化,導致產生一個具有相當大內存佔用空間的'A'實例。我可能最終會得到一個'A'的實例,我從來沒有真正將它用作'T'的實際意義上,而只是作爲具有不必要開銷的工廠。但也許這是簡化的代價。 – bluenote10

+0

看起來你需要在你的工廠中使用T的構造函數參數,所以我沒有看到你如何擁有這樣的工廠而沒有T的實例。除非像你說的那樣,你將參數包裝在類可以提供給工廠和T的子類的構造函數。 –

+0

從設計角度講purefly如果不是構建T的唯一方法,我不確定你需要執行這樣一個工廠。想必你有一些需要一個工廠,它可以是僅僅一個功能的方法:'MakeTsAndDoUsefulThings(工廠:()=> T)'。 然後在未來,如果我是你的代碼在客戶端做'SonOfT',發現我需要使用的功能,我會爲implment'SonOfT'工廠,可能在我的同伴對象,使這個呼叫:'MakeTsAndDoUsefulThings( SonOfT.defaultFactory)' 如果我從來不需要用這個方法,我將永遠不需要做工廠,這似乎確定。 –

1

添加一個表示類型參數:

trait Factory[Prod] { 
    def build(): Prod 
} 

trait Prod[Repr] { 
    def factory: Factory[Repr] 
} 

或者,如果你想 「強制執行」 的類型是一樣的(我不會做除非你從中得到一些東西):

trait Prod[Repr <: Prod[Repr]] { 
    def factory: Factory[Repr] 
} 

Then:

case class AConfig(a: Int, b: Int) 

case class A(config: AConfig) extends Prod[A] { 
    def factory = AFactory(config) 
} 

case class AFactory(config: AConfig) extends Factory[A] { 
    def build() = A(config) 
} 

val f0 = AFactory(AConfig(1, 2)) 
val p0 = f0.build() 
val f1 = p0.factory 
val p1 = f1.build() 
assert(p0 == p1)