2013-12-12 4 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을 작성합니다. 따라서, 나는이 간단한 문제에 대한 많은 상용구 인 3 개의 클래스로 끝납니다.

제 질문은 동일한 기본 목표를 달성하지만 더 간결한 (완전히 완전히) 다른 접근 방식이 있는지 여부입니다.

답변

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

디자인 관점에서 말하자면 T를 만드는 유일한 방법이 아닌 경우 그러한 팩토리를 시행해야하는지 확신 할 수 없습니다.'MakeTsAndDoUsefulThings (공장 :() => T)'아마도 당신은 함수가 될 수있는 공장을 필요로 몇 가지 방법이있다. 그럼 난 당신의 코드 클라이언트로'있도록 SonOfT'와 나는 아마 내 동반자 개체, SonOfT''에 대한 공장을 implment 것 기능을 사용하고이 호출 할 필요가 있음을 발견 한 경우, 미래에 : ('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] 
} 

다음 :

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)