Scala

2013-12-12 21 views
6

'daki fabrikanın uygulanmasını zorlaştırmanın özlü yolu T numaralı bir kaliteye sahip olduğumuzu varsayalım. Ne ulaşmanın en iyi yolu şudur:Scala

T bir uygulama T bir parametre içermeyen başlatma sağlayan bir olasılık, yani, muhtemelen uygulanmasını zorlamak zorunda sağlamak zorunda olmalıdır yazıyor
  • Herkes yapılandırılabilir bir fabrika.
  • Yalnızca gerçek başlatma parametrelerine (AT'un belirli bir uygulamasının) bağlı olan tüm mantık/veriler merkezi olarak ele alınmalı veya saklanmalıdır, ancak hem fabrikada hem de A'da bulunmalıdır.

elde etmek bkz en basit/özlü yolu bu (yaklaşık) bu fabrikaya bir fabrikada ve bağlantı T için bir özelliği eklemek olacaktır: Açıkçası bu gerçekten "zorlamaz

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" 
} 

"Bir fabrikanın uygulanması (alternatif bir uygulama mevcut olduğu sürece) ve" yanlış "bir TFactory'a bağlanan A örneklerinin üretilmesi mümkündür. Bu yaklaşımı sevmediğim şey, başlatma parametrelerinin tekrarıdır. Sık sık tüm parametreleri (örneğin yeni parametrelerin eklenmesini kolaylaştırmak için) saran başka bir sınıf AParams oluşturuyorum. Bu yüzden, bu basit problem için bir çok kazanın olduğu üç sınıfla bitiriyorum.

Sorum şu, aynı birincil hedeflere ulaşan ama daha özlü olan (belki tamamen) farklı bir yaklaşım olup olmadığıdır.

cevap

1

Gereksinimlerinizin tam amacını aldığımdan emin değilim ama bu davranış hakkında ne düşünüyorsunuz?

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) 

Çıktı:

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

Kesinlikle ilginç bir fikir, teşekkürler! Gördüğüm pratik bir problem, sezgisel olarak, bir fabrikanın hafif olduğu fikrini kaybedeceğimde, “T” nin gerçek uygulaması oldukça ağır olabilir. Çoğu zaman, kullanım durumlarımda gerçek bir 'A', büyük miktarda başlatma gerektirir ve bu da önemli bir bellek alanıyla 'A' örneğine neden olur. Muhtemelen genellikle bir “T” olmak için gerçek anlamda kullanamayacağım bir “A” örneğiyle sonuçlanırdım, ama gereksiz bir yük ile fabrika olarak. Ama belki bu basitleştirme için ödeme bedeli. – bluenote10

+0

Fabrikanızda T'nin yapıcı parametrelerini kullanmanız gerektiği gibi görünüyor, bu yüzden bir T örneğine sahip olmadan nasıl bir fabrikaya sahip olabileceğinizi göremiyorum. Siz dediğiniz gibi, parametrelerinizi Hem bir fabrika hem de T. alt sınıfının bir kurucusunun temin edilebileceği sınıf. –

+0

Tasarım bakış açısıyla safça konuşabileceğimi söyleyemem. Bu, fabrika inşa etmenin tek yolu değilse, böyle bir fabrikayı zorlamanız gerektiğinden emin değilim.Muhtemelen, sadece bir fonksiyon olabilen bir fabrikaya ihtiyaç duyan bir metodunuz var: 'MakeTsAndDoUsefulThings (factory:() => T)'. Öyleyse, eğer sizden bir müşteri olarak 'SonOfT' kodunu yapsam ve bu işlevi kullanmam gerektiğini bulursam, büyük olasılıkla benim arkadaşımın nesnesi olan SonOfT için bir fabrikayı icat edeceğim ve şu çağrıyı yapacağım: 'MakeTsAndDoUsefulThings (SonOfT.defaultFactory) Bu yöntemi kullanmam gerekmiyorsa, asla fabrikayı yapmam gerekmeyecek, ki bu iyi görünüyor. –

1

bir gösterim türü parametresi ekle: türü aynı kalmasını "zorlamak" istiyorsanız,

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

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

Veya (benim yapmayacağım Bunu bir şey kazanmadıkça):

Sonra:

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)