2012-06-02 2 views
3

수학 벡터 (실제 숫자 보유)에 대한 클래스를 작성하고 싶습니다. 나는 벡터 연산이 벡터의 차원에 상관없이 똑같다고 생각 했으므로 Vector2D, Vector3D, Vector4D과 같은 클래스를 작성하는 대신 Vector 클래스를 작성하고 싶습니다.임의의 크기의 수학 벡터에 대한 하나의 클래스

이제는 2D 벡터에 4D를 곱할 수 없으므로 dimension 필드에 대해 생각했습니다. 하지만 이제는 모든 작업에 대해 확인해야하므로 그보다 더 잘할 수 있는지 스스로에게 물었습니다. 이것은 제네릭이 내 마음에 온 것입니다. 하지만 다시 나는 Dimension이 난에 vectos를 사용하려면 모든 차원에 대한 Dimension 클래스를 작성해야 의미, 등등 단순히 Dimension.One, Dimension.Two의 기본 클래스이며 Vector<? extends Dimension>처럼 뭔가를해야합니다.

그래서 내 질문 :

런타임에 차원을 확인하지 않고도 임의의 차원의 벡터에 대해 하나의 클래스를 작성하는 방법이 있습니까?

+0

실무 구현으로 내 대답을 업데이트했습니다. 그것은 아마도 과잉 공격 일 것입니다.하지만 그것이 어떻게 수행 될 수 있는지를 보여줍니다. – Eric

답변

2

질문을 올바르게 이해하면 대답은 둘 다 가질 수 없다는 것입니다. 형식 시스템을 사용하여 올바른 차원을 확인한 다음 명시 적 유형이 확산되면 (제네릭은 도움이되지 않음) 최종 사용자가 작업을 수행 할 때마다 상태를 추적하고 동적 검사를 수행하기 위해 상태를 사용합니다. 벡터의 "차원"은 보유하고있는 요소의 수이기 때문에 기본 데이터 구조에서 어떻게 든 표현됩니다. 예를 들어 목록을 사용하여 벡터에 값을 저장하면 목록에 포함 된 요소의 수를 알 수 있습니다. 따라서 간단한 런타임 검사를 수행하는 것이 비용이 적게 들며 차원이 일치하지 않으면 예외가 발생할 수 있습니다. 이 솔루션은 유형 기반 솔루션보다 훨씬 유연하고 프로그래밍하기 쉽습니다.

+0

+1 "저렴한 ... [...] 프로그래밍하기 쉽습니다." 이것에 진정한 가치가 있습니다. –

+0

나는 그렇게 생각했다. 그러나 나는 단지 뭔가를 놓친다 고 생각했다. – IchBinKeinBaum

0

당신은

public static class Vector<V extends Vector<V>>{ 
    protected double[] components; 
    public final int dimensions; 
    private Class<V> klass; 

    protected Vector(int d, Class<V> klass) { 
     this.klass = klass; 
     this.components = new double[d]; 
    } 

    public double get(int x) { return components[x] } 
    protected void set(int x, double d) { components[x] = d } 

    public V clone() { 
     try { 
      V c = klass.newInstance(); 
      c.components = this.components.clone(); 
      return c; 
     } 
     catch(InstantiationException e1) {} 
     catch(IllegalAccessException e2) {} 
     return null; 
    } 

    public V add(V that) { 
     V sum = this.clone(); 
     for(int i = 0; i < dimensions; i++) 
      sum.components[i] += that.components[i]; 
     return sum; 
    } 

} 

그런 다음 각각의 경우 파생 몇 가지 흥미로운 제네릭으로 Vector 클래스를 작성할 수 : 결국

public static class Vector2D extends Vector<Vector2D>{ 
    public Vector2D() { 
     super(2, Vector2D.class); 
    } 
    public Vector2D(double x, double y) { 
     this(); 
     set(0, x); 
     set(1, y); 
    } 
} 
public static class Vector3D extends Vector<Vector3D>{ 
    public Vector3D() { 
     super(3, Vector3D.class); 
    } 
    public Vector3D(double x, double y, double z) { 
     this(); 
     set(0, x); 
     set(1, y); 
     set(2, z); 
    } 
} 
public static class Vector4D extends Vector<Vector4D>{ 
    public Vector4D() { 
     super(4, Vector4D.class); 
    } 
    public Vector4D(double w, double x, double y, double z) { 
     this(); 
     set(0, w); 
     set(1, x); 
     set(2, y); 
     set(3, z); 
    } 
} 

을, 특별한 경우가있다 - 예를 들어, 크로스 제품은 3 차원과 7 차원으로 만 존재합니다. 각각에 대한 구현이 있으면이를 해결합니다.

+0

불행히도 OP는 런타임시 각 메소드의 치수를 테스트해야합니다. – Howard

+0

@Howard : 사실이 아닙니다. OP는 'Vector3D'의 인스턴스를 사용합니다.이 인스턴스의 차원은 3입니다. Vector.add 메서드를 구현하려고 할 때 문제가 발생합니다. – Eric

+0

비슷한 아이디어가 있었지만 여전히 각 차원에 대한 수업을 작성해야했습니다. – IchBinKeinBaum

2

확인을 수행하는 메서드를 Dimension 클래스에 포함 할 수 있으며 벡터가 호환되지 않으면 Runtime Exception을 던집니다. 그런 다음 Dimension의 모든 메소드를 호출하여이 메소드를 호출하십시오. 코드가Dimension 클래스를 사용하는 코드는 검사로 흩어지지 않습니다.

Dimension.java :

public class Dimension { 
    class ONE extends Dimension {} 
    class TWO extends Dimension {} 
    class THREE extends Dimension {} 
    // [...] 
} 

Vector.java :

내가 제네릭 (그것은 내가 대답으로 게시하도록하겠습니다 이유입니다 작동) 사용하고자하는 이유
0

는 명확하게하려면
public class Vector<D extends Dimension> { 
    private double[] elements; 

    public Vector(double _elmts) { 
     elements = _elmts; 
    } 

    public void add(Vector<D> v) { /*...*/ } 
    public void subtract(Vector<D> v) { /*...*/ } 
} 

하지만 내 질문에 언급했듯이, 나는 처음부터 방지하고 싶었던 몇 가지 클래스를 만들어야합니다. 또한 오히려 추한 것입니다. elements이 사용자를 신뢰하는 것 외에 다른 적절한 차원을 유지할 수있는 방법이 없습니다.

에릭의 답변과 매우 흡사합니다.

+0

Dimension 클래스에서 수행하는 작업은 기본적으로 enum 클래스를 정의 할 때 Java가 자동으로 수행하는 작업입니다. 그러나 당신이 그곳에서 무엇을 하든지, 누군가는 항상 당신이 허용하는 것보다 더 높은 차원의 벡터를 사용하기를 원할 것입니다. – Wormbo

+0

이 버전에서는 비 변형 방법을 구현할 수 없습니다. – Eric