如何在不修改元素的情况下将数据与集合中的元素相关联?

时间:2016-12-28 15:07:32

标签: java design-patterns

通常,当我进行OpenGL编程时,我有一个这样的Mesh类:

public class Mesh {

    // General 3D stuff
    List<Vector3f> vertices = new ArrayList<>();
    List<Vector3f> normals = new ArrayList<>();
    List<Vector2f> texCoords = new ArrayList<>();

    // OpenGL-specific stuff
    protected int vertices;
    protected boolean dirty;
    protected int vertexArrayID = -1;
    protected int vertexBufferID = -1;

    ...

}

但是,我现在正在处理的应用程序更为通用,我希望将特定于OpenGL的内容与常规3D内容分开。例如,某人可能希望将Mesh存储为STL文件并将其打印为3D,或将其发送到Raytrace渲染器以使其看起来不错。在这种情况下,特定于OpenGL的数据是无用的。

换句话说,Mesh类的这种实现违反了单一责任原则。

现在,我能想到的一个解决方案如下:

public class Mesh {

    // General 3D stuff
    List<Vector3f> vertices = new ArrayList<>();
    List<Vector3f> normals = new ArrayList<>();
    List<Vector2f> texCoords = new ArrayList<>();
}

public class GlMesh extends Mesh implements GlDrawable {

    // OpenGL-specific stuff
    protected int vertices;
    protected boolean dirty;
    protected int vertexArrayID = -1;
    protected int vertexBufferID = -1;
}

但是,现在数据结构中仍然存在特定于OpenGL的对象,这些对象是从生成它的算法输出的。 Mesh生成器需要知道它应该创建GlMesh而不是Mesh,因此知道OpenGL渲染模块,我真的宁愿避免。

现在,我们可以这样做:

public class Mesh {

    // General 3D stuff
    List<Vector3f> vertices = new ArrayList<>();
    List<Vector3f> normals = new ArrayList<>();
    List<Vector2f> texCoords = new ArrayList<>();
}

public class GlMesh {

    // OpenGL-specific stuff
    protected int vertices;
    protected boolean dirty;
    protected int vertexArrayID = -1;
    protected int vertexBufferID = -1;
}

Map<Mesh, GlMesh> meshToGlMesh = (whatever)

然而,现在渲染系统必须进行大量的簿记才能将Mesh映射到相应的GlMesh,这只是一个问题。

有没有一种解决这个问题的好方法,我错过了?

2 个答案:

答案 0 :(得分:1)

我不是OpenGL程序员,所以我不知道这方面的所有问题,因此可能会让你误入歧途,但鉴于你所描述的内容,听起来像你&# 39;重新寻找工厂模式。

如果您的GLMesh对象需要像Mesh一样使用,那么它显然需要扩展Mesh(或者需要 facade < / {>在GLMesh前面的类,使其看起来像Mesh。)

同时,您将编写知道需要使用GLMesh的代码。该代码可以将GLMeshFactory传递给知道它将与GLMesh一起使用的代码,但可以知道它需要与Mesh一起使用。它将从Mesh获取MeshFactory个实例 - 通常是一个名为getInstance()的方法,采用您期望任何MeshFactory所需的任何参数来返回实例(您&# 39;我需要提前思考 - 最糟糕的情况是,除了你所知道的Map所需的任何额外数据之外,你最后传递Mesh

MeshFactory可以生成Mesh个实例,无论您现在正在做什么。 GLMeshFactory可以一遍又一遍地返回相同的实例(您在评论中暗示他们创建起来很昂贵)。工厂通常被理解为在适当的时候返回共享实例。

答案 1 :(得分:0)

这样的事情怎么样:

public class Mesh implements GlMeshSupplier{  
    private final List<Vector3f> vertices = new ArrayList<>();
    private final List<Vector3f> normals = new ArrayList<>();
    private final List<Vector2f> texCoords = new ArrayList<>();

    private GlMesh glMesh;

    @Override
    public GlMesh getGlMesh() {
        return glMesh;
    }

    public void createGlMesh(){
        glMesh = new GlMesh();
    }    

    public List<Vector3f> getVertices() {
        return vertices;
    }

    public List<Vector3f> getNormals() {
        return normals;
    }

    public List<Vector2f> getTexCoords() {
        return texCoords;
    }

    public class GlMesh extends Mesh{
        // OpenGL-specific stuff
        protected int ivertices;
        protected boolean dirty;
        protected int vertexArrayID = -1;
        protected int vertexBufferID = -1;

        private GlMesh(){}

        @Override
        public List<Vector3f> getVertices() {
            return Mesh.this.vertices;
        }

        @Override
        public List<Vector3f> getNormals() {
            return Mesh.this.normals;
        }

        @Override
        public List<Vector2f> getTexCoords() {
            return Mesh.this.texCoords;
        }
    }

}

public interface GlMeshSupplier {
    public GlMesh getGlMesh();
}

Mesh和GlMesh之间的替代映射:

    //class Mesh
    public Mesh(){
        this.vertices = new ArrayList<>();
        this.normals = new ArrayList<>();
        this.texCoords = new ArrayList<>();
    }

    private Mesh(List<Vector3f> vertices, List<Vector3f> normals, List<Vector2f> texCoords){
        this.vertices = vertices;
        this.normals = normals;
        this.texCoords = texCoords;
    }

    //class GlMesh
    private GlMesh(){
        super(Mesh.this.vertices, Mesh.this.normals, Mesh.this.texCoords);
    }

你的MeshGlMesh似乎彼此关系非常密切,这可能是合理制作这样的作品的理由。 Mesh可以独立于GlMesh创建。创建GlMesh后,它会将(Mesh)映射到封闭Mesh的属性。

方法getVertices()getNormals()getTexCoords()只是如何通过Mesh及其{{1}的网格方法访问相同属性的示例}}。

如果您要隐藏GlMesh中不应映射到Mesh的功能,您还可以使用GlMeshSupplier等供应商界面屏蔽Mesh