使用带有默认方法的新Java8接口

时间:2014-02-26 09:37:38

标签: java oop interface java-8 default-method

我对Java 8中的“新”接口有几个问题,我有以下代码:

public interface Drawable {
    public void compileProgram();

    public Program getProgram();

    public boolean isTessellated();

    public boolean isInstanced();

    public int getInstancesCount();

    public int getDataSize();

    public FloatBuffer putData(final FloatBuffer dataBuffer);

    public int getDataMode();

    public boolean isShadowReceiver();

    public boolean isShadowCaster();    //TODO use for AABB calculations

    default public void drawDepthPass(final int offset, final Program depthNormalProgram, final Program depthTessellationProgram) {
        Program depthProgram = (isTessellated()) ? depthTessellationProgram : depthNormalProgram;
        if (isInstanced()) {
            depthProgram.drawArraysInstanced(getDataMode(), offset, getDataSize(), getInstancesCount());
        }
        else {
            depthProgram.drawArrays(getDataMode(), offset, getDataSize());
        }
    }

    default public void draw(final int offset) {
        if (isInstanced()) {
            getProgram().use().drawArraysInstanced(getDataMode(), offset, getDataSize(), getInstancesCount());
        }
        else {
            getProgram().use().drawArrays(getDataMode(), offset, getDataSize());
        }
    }

    default public void delete() {
        getProgram().delete();
    }

    public static int countDataSize(final Collection<Drawable> drawables) {
        return drawables.stream()
                .mapToInt(Drawable::getDataSize)
                .sum();
    }

    public static FloatBuffer putAllData(final List<Drawable> drawables) {
        FloatBuffer dataBuffer = BufferUtils.createFloatBuffer(countDataSize(drawables) * 3);
        drawables.stream().forEachOrdered(drawable -> drawable.putData(dataBuffer));
        return (FloatBuffer)dataBuffer.clear();
    }

    public static void drawAllDepthPass(final List<Drawable> drawables, final Program depthNormalProgram, final Program depthTessellationProgram) {
        int offset = 0;
        for (Drawable drawable : drawables) {
            if (drawable.isShadowReceiver()) {
                drawable.drawDepthPass(offset, depthNormalProgram, depthTessellationProgram);
            }
            offset += drawable.getDataSize();   //TODO count offset only if not shadow receiver?
        }
    }

    public static void drawAll(final List<Drawable> drawables) {
        int offset = 0;
        for (Drawable drawable : drawables) {
            drawable.draw(offset);
            offset += drawable.getDataSize();
        }
    }

    public static void deleteAll(final List<Drawable> drawables) {
        drawables.stream().forEach(Drawable::delete);
    }
}

(许多人的一个实施)

public class Box implements Drawable {
    private FloatBuffer data;
    private Program program;

    private final float width, height, depth;

    public Box(final float width, final float height, final float depth) {
        this.width = width;
        this.height = height;
        this.depth = depth;
        data = generateBox();
        data.clear();
    }

    @Override
    public void compileProgram() {
        program = new Program(
                new VertexShader("data/shaders/box.vs.glsl").compile(),
                new FragmentShader("data/shaders/box.fs.glsl").compile()
        ).compile().usingUniforms(
                        UNIFORM_MODEL_MATRIX,
                        UNIFORM_VIEW_MATRIX,
                        UNIFORM_PROJECTION_MATRIX,
                        UNIFORM_SHADOW_MATRIX
                        );
    }

    @Override
    public Program getProgram() {
        return program;
    }

    @Override
    public boolean isTessellated() {
        return false;
    }

    @Override
    public boolean isInstanced() {
        return false;
    }

    @Override
    public int getInstancesCount() {
        return 0;
    }

    @Override
    public int getDataSize() {
        return 6 * 6;
    }

    @Override
    public FloatBuffer putData(final FloatBuffer dataBuffer) {
        FloatBuffer returnData = dataBuffer.put(data);
        data.clear();   //clear to reset data state
        return returnData;
    }

    @Override
    public int getDataMode() {
        return GL_TRIANGLES;
    }

    @Override
    public boolean isShadowReceiver() {
        return true;
    }

    @Override
    public boolean isShadowCaster() {
        return true;
    }

    private FloatBuffer generateBox() {
        FloatBuffer boxData = BufferUtils.createFloatBuffer(6 * 6 * 3);

        //putting lots of floats in boxData

        return (FloatBuffer)boxData.clear();
    }
}

问题:

  1. 从OOP角度来看,接口的实现是否正确,尤其是我通过公共getter存储/访问数据这一事实。
  2. 考虑到最基本的Drawable不会被实例化,也不会被细分,因此在伪代码isTessellated() = falseisInstanced() = falsegetInstancesCount() = 0中,声明是否有效具有此类属性的默认方法?

2 个答案:

答案 0 :(得分:1)

关于defaults方法的一点是,您不再需要创建一个抽象类来提供仅基于接口中的方法的某些功能。在这个术语中,您的设计是有效的。

有关详情,请访问Default Methods

答案 1 :(得分:0)

你所做的事情看起来似乎应该是有效的(我还没有真正使用Java 8的东西,但我知道它),但它并不是最好的面向对象设计。

这可以作为您扩展的抽象类更好地完成(特别是因为Box不扩展任何东西,但实现了drawable),因为那时你也可以将数据存储在类中,并具有实现它的方法。 / p>

现在,这些方法也可以在静态实用程序类中,用于它们在类中的所有用途。 (我知道他们会调用isTesselated,但静态实用程序类也可以这样做。)