2014-02-06 1 views
1

다음과 같은 특성 계층 구조가 있습니다. TraitA은 루트 특성이며 내 데이터 구조가 변경되지 않도록하려면 commonUpdateFunction() 함수에 일반 반환 형식이 있어야합니다. 이것이 최선의 방법인지 확실하지 않습니다. 나는 다른 두 가지 기능을 추가하여 그것을 확장하는 두 가지 특성을 가지고있다. 일부 클래스는 하나를 확장하고 일부 클래스는 다른 클래스를 확장하지만 일부 클래스는 두 클래스를 모두 확장해야합니다.여러 수준의 특성을 확장 할 때 불변의 반환 형식 상속

그러나 지금은 데이터 구조를 새로운 것으로 업데이트 할 때 실제로 올바른 유형을 얻으려는 경우 불법 상속을받는 일반적인 유형의 문제로 인해 문제가 발생합니다.

또한이 일반적인 유형 때문에 TraitA을 매개 변수로 전달할 수없는 것 같습니다.

trait TraitA[T <: TraitA[T]] 
{ 
    self : T => 

    def commonUpdateFunction() : T 
} 

trait TraitB extends TraitA[TraitB] 
{ 
    def someFunctionB() : Integer = { /// some code } 
} 

trait TraitC extends TraitA[TraitC] 
{ 
    def someFunctionC() : Unit = { /// some code } 
} 

class ClassB extends TraitB 
{ 
    def commonUpdateFunction() : ClassB = { /// some code } 
} 

class ClassC extends TraitC 
{ 
    def commonUpdateFunction() : ClassC = { /// some code } 
} 

class ClassA extends TraitB with TraitC //**this causes illegal inheritance** 
{ 
    def commonUpdateFunction() : ClassA = { /// some code } 
} 

동시에 적합한 유형의 데이터 구조의 불변 갱신하면서 2 특징에 상속을 달성하기위한 적당한 방법은 무엇인가? JVM을 비록

class ClassA extends TraitB with TraitC { 
    def commonFunction() : ClassA = { /// some code } 
    def commonFunction() : ClassB = { /// some code } 
    def commonFunction() : ClassC = { /// some code } 
} 

가 과부하 허용 않습니다

답변

3

유형 매개 변수를 여기 문제가되지 않습니다, 문제는 ClassA 시도는 반환 형식에 따라 다릅니다 commonFunction() 3 부에 혼합하는 것입니다 반환 유형은 컴파일 타임에는 허용되지 않습니다. 특히 혼동이 너무 많습니다 (특히 형식 유추가 관련된 경우).

해결책은 종종 f 한정 경계 다형성 (commonUpdateFunction()과 같이)을 사용하는 것이지만 모든 commonFunction() 정의가 구체적이라는 가정하에 여기에서 수행하는 방법을 보여주는 것은 불가능합니다.

"실제"코드를 더 많이 볼 때 도움이됩니다.


UPDATE : 코멘트에서 새로운 정보를 바탕으로.

매개 변수 대신 추상적 유형 구성원으로 더 쉽게 알 수 있습니다. Repr ("Repr"esentation 용)은 흔히 사용되는 규칙이며 collections lib에 사용됩니다. 이 추상 타입 멤버가 바인딩되어 있는지 확인하십시오!

스틱 여기뿐만 아니라의 다른 공통 속성 :

trait Employee { 
    type Repr <: Employee 

    def name : String 
    def id : Int 

    def withName(name: String) : Repr 
    def withId(id: Int) : Repr 
} 

하위 특성이 유사한 패턴을 따른다. 시그니처를 유지하는 다른 추상 멤버를 다시 선언 할 필요가 없습니다. 여기에서 유형을 다듬을 때 다른 멤버를 소개 할 수도 있습니다.

trait ManagingEmployee extends Employee { 
    type Repr <: ManagingEmployee 
    def numberOfReports: Int 
    def withNumberOfReports(x: Int) : Repr 
} 

trait SkilledEmployee extends Employee { 
    type Repr <: SkilledEmployee 
    def skill: String 
} 

이제 우리 유형 나무의 잎 노드를 콘크리트로 만드십시오. (매크로가 도움이 될 수 있지만, 그것은 다른 질문입니다.) 슬픈 듯이 중복 될 것입니다.

nameid는 클래스 PARAMS에 의해 콘크리트를 제작하는 방법을 참고는 Repr 유형이 = 기호를 통해 명시 적으로 이루어지며, 추상 메소드가 명시 적으로 각 잎 클래스에서 다시 정의 할 수 있습니다 :

case class HrManager(
    name   : String, 
    id    : Int, 
    numberOfReports : Int 
) extends ManagingEmployee { 
    type Repr = HrManager 
    def withName(name: String) = this.copy(name = name) 
    def withId(id: Int) = this.copy(id = id) 
    def withNumberOfReports(x: Int) = this.copy(numberOfReports = id) 
} 

case class Technician(name: String, id: Int) extends SkilledEmployee { 
    type Repr = Technician 
    def withName(name: String) = this.copy(name = name) 
    def withId(id: Int) = this.copy(id = id) 
    val skill = "programming" 
} 

case class TechnicalManager(
    name   : String, 
    id    : Int, 
    numberOfReports : Int 
) extends SkilledEmployee with ManagingEmployee { 
    type Repr = TechnicalManager 
    def withName(name: String) = this.copy(name = name) 
    def withId(id: Int) = this.copy(id = id) 
    def withNumberOfReports(x: Int) = this.copy(numberOfReports = id) 
    val skill = "software architecture" 
} 
+0

나는 스칼라 초심자이기 때문에 몇 가지 중요한 디자인 원칙을 놓칠 수 있습니다. 내가 알아 내려고 애 쓰고있는 것은 전통적인 OO 다형성을 달성하는 동시에 데이터 객체를 불변으로 유지하는 것입니다. 이것은 전형적인 예입니다 :'Employee'는'name'과'employeeId'를 가진 추상 클래스로서,'Technician'과'Manager'처럼 클래스가 몇 개 확장됩니다. 'name'이나'employeeId'를 갱신하는 메소드는 불변이 될 경우 동일한 유형의 또 다른 인스턴스를 생성해야합니다. 반면 시스템의 나머지 부분에는'Employee'를 취하는 메서드가 있습니다. – jbx

+0

이 시나리오에서는'Employee'를 특성으로 만들고 Technician 및 Manager에 대한 case 클래스 하위 유형을 지정할 수 있습니다. 'commonUpdateFunction'에 대해했던 것처럼'withName'과'withId'를 선언하고'copy' 메소드의 관점에서 case 클래스를 정의하십시오. 당신이'commonFunction'과'commonUpdateFunction'을 당신의 예제에서 같은 의미로 쓰는 지 궁금합니다. 왜냐하면 지금 당장은 매우 다르니까 –

+0

예, 저의 실수였습니다. 결정된. 그렇습니다. 문제는 완전히 관련이없는 클래스의 메서드에 대한 인수로 'Employee'를 사용해야하는 다른 곳에서 발생합니다. 그것이 어떤 유형의 직원인지 상관하지 않습니다. 현재로서는 불변 클래스의 실제 타입을 결정하기위한 해킹 인'[T] '가 있기 때문에 타입을 지정해야한다는 오류가 발생합니다. – jbx

관련 문제