2011-01-31 8 views
3

구체적인 하위 클래스를 생성하는 추상 클래스에서 생성자를 정의하려고합니다.기본 추상 클래스에서 서브 클래스 구성하기

abstract class A { 
    type Impl <: A 
    def construct() : Impl = { 
    val res = new Impl() //compile error: class type required but A.this.Impl found 
    // do more initialization with res 
    } 
} 

class B extends A {type Impl = B} 
class C extends A {type Impl = C} 
//... 
val b = new B 
b.construct() // this should create a new instance of B 

무엇이 잘못 되었나요? 이것은 구현할 수 있습니까? 편집 : 설명 : 구문을 추상화하고 싶습니다. new Bnew C을 하위 클래스 또는 컴패니언 개체에서 개별적으로 호출하고 싶지 않습니다.

+0

새 B 또는 새 C를 부르는 것을 피함으로써 어떤 이점이 있습니까? – Monkey

+0

많은 서브 클래스 (B, C, D, ...)가있을 수 있으며 중복/상용구 코드를 피하기를 원합니다. – Adrian

+0

당신이하고 싶은 일을 할 수있는 유일한 방법은 리플렉션을 사용하는 것입니다. 나는 나의 대답에서 말했듯이 훌륭한 생각이 아니다. – Monkey

답변

1

당신은 추상 클래스가 아닌 companion 오브젝트에 생성자를 넣을 것입니다. 이처럼 : 이제

object A { 
    def apply(i:Int):A = new B(...) 
    def apply(s:String):A = new C(...) 
} 

, 당신은 예를 들어, A(42), 또는 A("foobar")를 호출하여 A의 인스턴스를 만들 수 있습니다. 물론 문자열 및 정수 매개 변수는 예제 일뿐입니다. 모든 생성자의 매개 변수가 같은 유형 인 경우이 오버로드가 작동하지 않습니다. 이 경우 쉽게 다른 메서드를 만들고 apply이 아닌 다른 메서드를 호출 할 수 있습니다.

2

새 인스턴스를 만들려면 명시 적으로 생성자를 호출해야합니다.

abstract class A { 

    def newInstance(): this.type; 

    def construct() : this.type = { 
    val res = newInstance() 
    } 
} 

class B extends A { 
    def newInstance() = new B() 
} 

Scala는 런타임에 유형을 지우므로 클래스 생성 당시의 Impl을 알 수있는 방법이 없습니다.

+0

이것은 작동하지 않습니다. this.type은 타입 B와는 다른 인스턴스 자체의 싱글 톤 타입이기 때문에'new B()'에서 컴파일 에러를 보게 될 것입니다. 싱글 톤 타입의 객체는 만들 수 없습니다. – fikovnik

1

리플렉션을 사용하여 새 인스턴스를 만들 수 있습니다. 이런 식으로 뭔가 효과가 있지만 내 의견으로는 문제가되지 않습니다. 한 가지만 말하면 런타임에 적절한 생성자가 있는지 확인할 수 있습니다.

def newInstance[T:ClassManifest]:T = { 
    val klass = implicitly[ClassManifest[T]].erasure 
    val constr = klass.getConstructors()(0) 
    constr.newInstance().asInstanceOf[T] 
} 

abstract class A { 
    def construct(implicit cm:ClassManifest[this.type]): this.type = { 
    val res = newInstance[this.type] 
    res 
    } 
} 

class B extends A 
+0

당신은 스칼라에서 이런 종류의 일을 할 수있는 가장 좋은 방법입니다. –

+0

모든 언어로 제공됩니까? – Raphael

+0

왜 여기에 매니페스트를 사용하나요? 삭제가 없으며 매개 변수화 된 유형이 없습니다. – Adrian

0

이렇게 보이지 않습니다. Scala 책 (Oderski, Spoon, Venners 저) 에 따르면 추상 형식의 인스턴스를 만들 수 없습니다. 참조 : 추상 유형 장, 통화 사례 연구. 이것은 나중에 "가상 클래스"로 지원 될 수 있습니다.

abstract class A($params) { 
    // do common initialisation here 
    def construct() : A 

    def foo(...) = { 
    ... 
    val bar = construct() 
    ... 
    } 
} 

class B($moreparams) extends A($someparams) { 
    // do special initialisation here 
    def construct() = new B() 
} 

당신이 지금 가지고있는 모든 reduandancy는 서브 클래스마다 정확히 한 줄은 다음과 같습니다

0

나는 다음과 같은 패턴을 제안한다. 나는 b) 반사를 사용하지 않는 실용적인 솔루션 (정적 인 시스템이 당신에게 제공한다는 것을 본질적으로 모두 깨트 렸음)에 대해 지불 할 작은 가격으로 생각한다.

나는 왜 construct 안에 A이 필요한지 궁금합니다. 비린내가 난다.

0

내 의견은 Monkey 왼쪽에 있습니다.

abstract class A[T <: A[T]] { this: T => 

    def newInstance(): T; 

    def construct(): T = { 
    val res = newInstance() 
    res 
    } 

    def some(): T = this 
} 

class B extends A[B] { 
    def newInstance() = new B() 
} 

은 아마도 더 나은 솔루션이있다, 그러나 이것은 지금까지 내가 찾은 것입니다 :이 문제를 해결하는 방법을 한 가지 방법은 자기 유형과 함께 Curiously Recurring Template Pattern (CRTP)를 사용하는 것입니다.

관련 문제