使用泛型方法创建不可变基础

时间:2014-02-09 20:58:00

标签: java android inheritance immutability

我有一个基类:

public abstract class BasePiece extends Serialisable {
    public final Position[] shape;
    public final Position position;

    public abstract Position[] getInitialShape();

    public BasePiece() {
        position = new Position(0, 0);
        shape = getInitialShape();
    }
    public BasePiece(Position pos, Position[] initialShape) {
        position = pos;
        shape = initialShape;
    }

    public BasePiece Moved(Position offset) {
        return BasePiece(position.add(offset), shape);
    }

    public BasePiece Rotated() {
        return BasePiece(position, shape.Rotated());
    }
}

但是我希望Moved和Rotated返回继承此类的类的实例。我对Java很新,并且有一些C#的经验,我试着做以下事情:

public <T extends BasePiece> T Moved(Position offset) {
    return T(position.add(offset), shape);
}

public <T extends BasePiece> T Rotated() {
    return T(position, shape.Rotated());
}

有没有办法做到这一点?我最初尝试解决这个问题的方法是使形状和位置不再是最终的,并使Moved和Rotated Move和Rotate方法改变这种状态。我真的想让对象变成不可变的,因为它会使我的应用程序的大部分内容更易于管理

2 个答案:

答案 0 :(得分:1)

我认为这与仿制药几乎没有关系。您可以将方法声明保留为:

public BasePiece Moved(Position offset) {
        return BasePiece(position.add(offset), shape);
}

并且在扩展它的类中:

class ExtendPiece extends BasePiece {

    @Override
    public BasePiece Moved(Position offset) {
            return ExtendPiece(position.add(offset), shape);
    }

}

ExtendPiece可以向下投放到BasePiece

但当然你必须自己施展:

ExtendPiece e = (ExtendPiece) obj.Moved(..);

修改

一个快速的解决方法是使用所谓的双重调度:

使每个子类实现方法newInstance()在基类中是抽象的。在ExtendedPiece中:

public BaseClass newInstance(Position pos, Position[] initialShape){
    return new ExtendedPiece(pos, initialShape);
}

和抽象方法的代码为:

public BasePiece Moved(Position offset) {
     return this.newInstance(position.add(offset), shape);
}

答案 1 :(得分:1)

我假设您只想在基类中定义一次泛型方法,并让它们在您的子类中自动运行。

是的,这可以用Java完成。它比C#中的更冗长,但是你可以这样做。

首先,您必须将此添加到您的基类声明中:

public abstract class BasePiece<T extends BasePiece<T>> implements Serializable {
    ...
}

然后,在你的方法中,这样做(它涉及反射,你必须导入java.lang.reflect.Constructor):

public T Moved(Position offset) {
        //Use reflection to invoke the constructor
        @SuppressWarnings("unchecked")
        Constructor<T> constructor = (Constructor<T>) this.getClass().getConstructor(Position.class, Position[].class);
        T newInstanceOfSpecificType = null;
        try {
            // Cast result to T, which will be the subclass
            newInstanceOfSpecificType = (T) constructor.newInstance(position.add(offset), shape);
        } catch (Exception e) {
            if (e instanceof NoSuchMethodException) {
                throw new RuntimeException("You forgot to declare the appropriate constructor in " + this.getClass().getSimpleName() + "!\n");
            }
            e.printStackTrace();
        }
        return newInstanceOfSpecificType;
    }

一个问题:您必须确保在所有子类中使用签名(Position,Position [])定义构造函数,并且您必须专门声明子类,如下所示:

public class ExtendedPiece extends BasePiece<ExtendedPiece> {

    public ExtendedPiece(Posistion position, Position[] shape) {
        return super(position, shape);
    }

}