2015-06-10 2 views
2

Я не могу использовать метод цепочки нескольких классов векторов, которые строятся друг на друге. Я хочу расширить этот класс.Метод цепочки + наследование 2 или более раз

Здесь 2d один:

public class Vec2 < C extends Vec2 > { 

    public double x, y; 

    public Vec2() { 
    } 

    public Vec2(double x, double y) { 
     this.x = x; 
     this.y = y; 
    } 

    public C add(double x, double y) { 
     this.x += x; 
     this.y += y; 
     return (C) this; 
    } 

} 

Это для вектора с г элемента.

class Vec3 < C extends Vec3 > extends Vec2<Vec3> { 

    double z; 

    public Vec3(){} 

    public Vec3(double x, double y, double z) { 
     super(x, y); 
     this.z = z; 
    } 

    public C add(double x, double y, double z) { 
     super.add(x, y); 
     this.z += z; 
     return (C) this; 
    } 
} 

Но когда это использовать Vec3 то, как только я использую метод из vec2 два раза подряд, то он возвращает vec2.

Vec3<Vec3> a = new Vec3<>(); 
// ------------------------------------------------->.add() in Vec2 cannot be aplied 
a.add(10, 20).add(10, 20, 10).add(10, 20).add(10, 20).add(10, 10, 20); 

Я не хочу, чтобы написать класс, как это:

class Vec3 extends Vec2<Vec3> { 

    // constructor etc. like before... 

    public Vec3 add(double x, double y, double z) { 
     super.add(x, y); 
     this.z += z; 
     return this; 
    } 
} 

Причина тогда, когда я делаю vec4, например, я должен переопределить каждый метод Vec3.

Есть ли способ (синтаксис) вокруг этой проблемы? Где бы ни было, что Он вернет правильный класс.

+0

[Это] (HTTP://stackoverflow.com/questions/1069528/method-chaining-inheritance-don-t-play-well-together), но я не уверен, сколько уровней оно может опуститься. –

+0

Я не думаю, что вы можете уйти далеко, и это _Where независимо от того, что Он продолжает возвращать правильный класс, практически невозможно без участия разработчиков. –

ответ

2

Проблема в том, что у вас было много «сырых» типов в ваших определениях, например.

Vec2 < C extends Vec2 > 
       ---- 
       raw type! 

После нескольких раундов, вы достигнете сырого типа, а стирание делает C так же, как Vec2.


Мы можем сделать следующее, используя тип переменной This как «самостоятельного типа»

public class Vec2<This> { 

    public This add(double x, double y) { 
     this.x += x; 
     this.y += y; 
     return (This) this; 
    } 

} 

public class Vec3<This> extends Vec2<This> { 

    public This add(double x, double y, double z) { 
     super.add(x, y); 
     this.z += z; 
     return (This) this; 
    } 
} 

public class Vec4<This> extends Vec3<This> { 

etc. 

Но секундочку, как мы поставляем This в Vec3?

Vec3<Vec3<Vec3<......>>> ??? 

Мы можем использовать вспомогательный класс

public class V3 extends Vec3<V3>{} 

Теперь все это работает; все add() методы V3 возвращения V3

V3 a = new V3(); 
    a.add(10, 20).add(10, 20, 10).add(10, 20).add(10, 20).add(10, 10, 20); 
+0

Я думаю, проблема в java ... – clankill3r

+1

@ clankill3r - ну, вы не можете спорить с этим – ZhongYu

+0

, вы в основном правы, за исключением того, что вы не указываете тип * саморегуляции *. Используйте это вместо этого: 'Vec2 >' и оставить код OP как-то (т.е. вернуть 'C') – Bohemian

0

Вы не можете реализовать свой код в точности так, как вы хотели, но следующие компилирует и я считаю, фиксирует свое намерение:

interface Vec<C extends Vec<C>> { 
    C add(C c); 
} 

class Vec2 implements Vec<Vec2> { 
    public double x, y; 
    public Vec2() { 
    } 

    public Vec2(double x, double y) { 
     this.x = x; 
     this.y = y; 
    } 

    public Vec2 add(Vec2 c) { 
     this.x += c.x; 
     this.y += c.y; 
     return this; 
    } 
} 

static class Vec3 implements Vec<Vec3> { 
    Vec2 vec2; 
    double z; 
    public Vec3() { 
     this(0,0,0); 
    } 

    public Vec3(double x, double y, double z) { 
     vec2 = new Vec2(x, y); 
     this.z = z; 
    } 

    public Vec3 add(Vec3 c) { 
     vec2.add(new Vec2(c.vec2.x, c.vec2.y)); 
     this.z += z; 
     return this; 
    } 
}