2012-02-07 1 views
10

저의 목표는 형질 혼합을 사용하여 기존 자바 클래스 내에서 스칼라 코드를 향상시키는 것입니다. 예를 들어 java.awt.Rectangle.translate (dx, dy)와 같은 메소드를 java.awt.geom.Ellipse2D 클래스에 추가 할 수 있습니다. 타원 구성 할 때특성을 사용하여 Java 클래스를 향상시키는 방법, 내부 특성을 Java 필드로 선언하는 방법은 무엇입니까?

trait RectangleLike { 
    var x: Double // abstract vals to correspond to java class fields 
    var y: Double // I need these vars to refer to them inside translate method 
    def translate(dx: Double, dy: Double) { 
    x = x + dx 
    y = y + dy 
    } 
    // more concrete trait methods here 
} // defines without errors in scala REPL 

는 그런 특성을 사용합니다 :이를 위해 나는 다음과 같은 특성 만들

그러나

val egg = new java.awt.geom.Ellipse2D.Double(5, 10, 20, 30) with RectangleLike 

을 내가 스칼라 REPL에 위의 스크립트를 실행할 때를 나는 다음과 같은 출력을 얻을

<console>:8: error: overriding variable x in trait RectangleLike of type Double; 
variable x in class Double of type Double has incompatible type; 
other members with override errors are: y 
val egg = new java.awt.geom.Ellipse2D.Double(5, 10, 20, 30) with RectangleLike 

이 오류는 스칼라가 개인 필드 및 getter/setter 메소드 쌍으로 vars를 구현하는 방식 때문인 것으로 의심됩니다. 내가 할 수있는 일을 성취하려고 노력하고 있습니까? 특성에 자바 클래스 필드를 정의한 다음 구체적인 특성 메서드 내부에서이를 참조 할 수있는 또 다른 방법이 있습니까? 사전에

감사 잭 디 마스

답변

8

네, 행할 수 있지만, 대신, 당신은 것 (어쨌든 대부분 나쁜 생각이다)에 혼합 할 클래스의 private 필드에 액세스하려고의 RectangleLike의 자체 유형을 java.awt.geom.RectangularShape으로 선언하여 예를 들어 자신의 특성을 사용할 수 있습니다. Ellipse2D.Double뿐 아니라 Rectangle2D.Double도 있습니다. 여기 그것이 작동하는 방법

은 다음과 같습니다

trait RectangleLike { 
    self: java.awt.geom.RectangularShape => 

    def translate(dx: Double, dy: Double) { 
    setFrame(getX + dx, getY + dy, getX + getWidth, getY + getHeight) 
    } 
} 

object Test { 
    val foo = new java.awt.geom.Ellipse2D.Double with RectangleLike 
} 

당신이 필요한 getter 및 setter 같은 모든 해당 메서드에 액세스 할 수 있습니다 당신의 특성의 자기 형을 선언 self: java.awt.geom.RectangularShape => 말을하면, 당신의 특성을 사용 가능 RectangularShape의 모든 자손이며, 자신의 특성 인 "subtype"이 RectangularShape 인 클래스에만 mixin으로 사용할 수 있도록 특성을 "제한"합니다. 위의 시나리오에

대안

뿐만 아니라 일반적인 패러다임 당신의 RectangularShape의 소위 보기을 사용하고 있습니다. 이를 위해 클래스

class RichRectangularShape(shape: java.awt.geom.RectangularShape) { 
    def translate(dx: Double, dy: Double) { 
    shape.setFrame(shape.getX + dx, shape.getY + dy, 
        shape.getX + shape.getWidth, shape.getY + shape.getHeight) 
    } 
} 

스칼라 암시 다른 형식의 개체로 한 형식의 개체를 볼 수있는 방법이 있습니다를 선언합니다. 해당 유형에서 선언되지 않은 객체에서 메서드를 호출하면 컴파일러는이 메서드를 제공하는 형식을 찾으려고 시도하며 특히 암시 적 변환을 찾아 원본 개체를 후자의 유형. 이 작업을 위해, 일반적으로이 같은 무언가로 RichRectangularShape의 동반자 객체를 선언합니다 : 다음

object RichRectangularShape { 
    implicit def mkRRS(shape: java.awt.geom.RectangularShape): RichRectangularShape = 
    new RichRectangularShape(shape) 
} 

:

scala> import RichRectangularShape._ 
import RichRectangularShape._ 

scala> val foo = new java.awt.geom.Ellipse2D.Double 
foo: java.awt.geom.Ellipse2D.Double = [email protected] 

scala> foo.translate(5,2) 

scala> foo.getX 
res1: Double = 5.0 

scala> foo.getY 
res2: Double = 2.0 

scala> :t foo 
java.awt.geom.Ellipse2D.Double 
+1

@forNelton impressive! 정말 고생 했어요. 고마워요. 암시 적 관점을 연구해야합니다. – ideathbird

+0

당신을 진심으로 환영합니다. 응용 프로그램의 유형에 따라 첫 번째 방법이 더 적절할 수 있습니다. 왜냐하면 메서드 호출이 모든 암시 적 번거 로움없이 빠른 속도로 진행될 수 있기 때문입니다. – fotNelton

0

참으로 인상적인 설명과 예제를!

이 접근 방식에는 약간의 문제가 있습니다. translate 메서드에는 피할 수있는 실제 계산이 포함되어 있습니다. 예,이 경우 매우 간단하지만 일반적으로 이러한 방법은 복잡하고 심각한 개발로 이어질 수 있습니다.따라서 다음 접근 방식을 제안합니다.

trait RectangleLike extends java.awt.geom.RectangularShape { 
    def translate(dx: Int, dy: Int): Unit = { 
     val rect = new java.awt.Rectangle 
     rect.setRect(getX, getY, getWidth, getHeight) 
     rect.translate(dx,dy) 
     setFrame(rect.getX, rect.getY, rect.getWidth, rect.getHeight) 
     } 
} 

이렇게하면 원본 translate을 사용하고 있습니다.

관련 문제