多级子类和方法链接

时间:2014-01-17 14:11:01

标签: java generics inheritance subclass chaining

我正在研究以下结构:

  • Buffer
  • XBuffer扩展Buffer
  • XYBuffer扩展XBuffer

所有对象都应该是可实例化的,所以没有abstract,以支持向前兼容性。

我想出了以下内容,我将在下面描述陷阱/问题:

public class Buffer<S extends Buffer<S>> {
    protected final int bufferType;
    protected final int bufferDataType;

    protected int bufferId;
    protected boolean created;

    public Buffer(final int bufferType, final int bufferDataType) {
        this.bufferType = bufferType;
        this.bufferDataType = bufferDataType;
    }

    @SuppressWarnings("unchecked")
    public S create() {
        assertNotCreated();
        bufferId = GL15.glGenBuffers();

        created = true;
        return (S)this;
    }

    @SuppressWarnings("unchecked")
    public S bind() {
        assertCreated();
        GL15.glBindBuffer(bufferType, bufferId);

        return (S)this;
    }

    @SuppressWarnings("unchecked")
    public S fillData(final float[] data) {
        assertCreated();

        FloatBuffer dataBuffer = BufferUtils.createFloatBuffer(data.length).put(data);
        dataBuffer.flip();
        GL15.glBufferData(bufferType, dataBuffer, bufferDataType);

        return (S)this;
    }

    public void delete() {
        assertCreated();

        GL15.glDeleteBuffers(bufferId);
    }

    public int getBufferId() {
        return bufferId;
    }

    public boolean hasBeenCreated() {
        return created;
    }

    private void assertCreated() {
        if (!hasBeenCreated()) {
            throw new RuntimeException("Buffer has not been created.");
        }
    }

    private void assertNotCreated() {
        if (hasBeenCreated()) {
            throw new RuntimeException("Buffer has been created already.");
        }
    }

    @Override
    public String toString() {
        return "Buffer(" + bufferType + ", " + bufferDataType + ", " + bufferId + ", " + created + ")";
    }
}

public class ArrayBuffer<S extends ArrayBuffer<S>> extends Buffer<S> {
    public ArrayBuffer(final int bufferDataType) {
        super(GL15.GL_ARRAY_BUFFER, bufferDataType);
    }
}

public class StaticDrawArrayBuffer extends ArrayBuffer<StaticDrawArrayBuffer> {
    public StaticDrawArrayBuffer() {
        super(GL15.GL_STATIC_DRAW);
    }
}

现在发生以下情况:

  • 实例化任何最低级别的子类都可以正常工作,StaticDrawArrayBuffer按预期工作。
  • ArrayBuffer无法按预期工作,因为我不能在不使用泛型的情况下实例化它。 (请记住:此处使用的泛型仅用于帮助我,而不是实际提供通用功能
  • Buffer无法正常工作,问题与ArrayBuffer相同。

我想要什么?

  • 我现在拥有的一切,除了我可以在不使用泛型的情况下实例化BufferArrayBuffer

我该怎么做?

为了澄清更多,这些陈述应该全部编译:

  • Buffer buffer = new Buffer().create().bind();
  • ArrayBuffer arrayBuffer = new ArrayBuffer().create.bind();
  • StaticDrawArrayBuffer staticDrawArrayBuffer = new StaticDrawArrayBuffer().create.bind()

如果我根本不使用任何泛型,那么new ArayBuffer().create()将返回Buffer,导致无法将其分配给ArrayBuffer。它确实保留了Buffer方法的链接,但如果链包含仅ArrayBuffer可用的方法,它还会中断。

如果它有帮助,我有能力使用Java 8,如果它几乎是无bug的(现在应该是现在,我想?),考虑到这个项目无论如何都不会看到真正的日光。

3 个答案:

答案 0 :(得分:1)

Covariant返回类型而不是泛型呢?

public class ArrayBuffer extends Buffer {
    public ArrayBuffer(final int bufferDataType) {
        super(GL15.GL_ARRAY_BUFFER, bufferDataType);
    }

    public ArrayBuffer create() {
        super.create();
        return this;
    }
    public ArrayBuffer bind() {
        super.bind();
        return this;
    }
}

public class StaticDrawArrayBuffer  extends ArrayBuffer {
    public StaticDrawArrayBuffer() {
        super(GL15.GL_STATIC_DRAW);
    }


    public StaticDrawArrayBuffer bind() {
        super.bind();
        return this;
    }
}

AFAIK现在应该编译:

Buffer buffer = new Buffer().create().bind();
ArrayBuffer arrayBuffer = new ArrayBuffer().create().bind();
StaticDrawArrayBuffer staticDrawArrayBuffer = new StaticDrawArrayBuffer().create().bind()

答案 1 :(得分:0)

一种可能性是将不使用泛型的代码部分与通用继承树分开(在我看来,这是一种笨拙的开头,但这主要是Java设计方式的问题,将泛型添加到语言中时所做的设计选择。)

我的意思是执行以下操作:

public class Buffer extends BaseBuffer<Buffer> {
    public Buffer(final int bufferType, final int bufferDataType) {
        super(bufferType, bufferDataType);
    }    
}

public class ArrayBuffer extends BaseArrayBuffer<ArrayBuffer> {
    public ArrayBuffer(final int bufferDataType) {
        super(bufferDataType);
    }
}

BaseBufferBaseArrayBuffer是您拨打BufferArrayBuffer的课程。

(虽然看起来你可能已经根据你的一条评论做了这个吗?)

此方法的问题在于,您无法将StaticDrawArrayBuffer作为ArrayBufferArrayBuffer作为Buffer传递(或将其存储在这些类型的变量中)因为它们不再是那些特定类型的子类。您必须使用类似BaseArrayBuffer<StaticDrawArrayBuffer>BaseBuffer<ArrayBuffer>的内容。

答案 2 :(得分:0)

我强烈建议您重新考虑您的架构。实例化子项和父类是一个坏主意。假设,有一天你想改变父行为(因为你使用它并且要求已经改变),同时让孩子完好无损。那么呢?

改用策略。指定缓冲区接口(为什么需要它?它应该做什么?)并为每个实例提供一个策略来实现它们的目的。

然后你将只有包含Buffers和Strategies的Buffer来实现你的逻辑:

public interface BufferingStrategy
{
    public Buffer create() ;
    public Buffer bind();
    public Buffer fillData(final float[] data);
}