2017-08-01 46 views
3

比方说,我有三个班,SolidFace,并Edge被定义如下:是否存在处理这种共享资源情况的设计模式或基本的面向对象原则?

class Solid{ 
    public: 
     // perform an action on a single edge. 
     void addFillet(int edgeNum); 
     // perform an action on a single face 
     void addBore(int faceNum); 
     // perform an action on all faces and edges 
     void move(Pos newPosition); 
    private: 
     std::vector<Edge*> edges; 
     std::vector<Face*> faces; 
}; 

class Face{ 
    public: 
     // will modify a subset of edges 
     virtual void changeHeight(int newHeight) = 0; 
    private: 
     int myNum; 
     std::vector<Edge> edges; 
} 

class Edge{ 
    public: 
     virtual void changeLength(int newLength) = 0; 
    private: 
     int myNum; 
     int length; 
} 
在这个例子中

Solid管理着的Edge S '超'。 Solid管理的每个Face将具有Solid.edges的“子集”。此外,任何两个Solid.faces可能有一个共同的Edge

我的问题:有没有任何设计模式或面向对象的一般原则来处理这种情况?我如何管理Solid.edgesFace.edges之间的关系?更具体地说

+3

那么通常你只能将边缘缓冲区存储在Solid对象中,并且对于每个Face存储它拥有的Edge的索引。 (与存储顶点的传统计算机渲染并行绘图) – meowgoesthedog

+1

由于@meowgoesthedog提到,这与OpenGL处理​​[Vertex Arrays](https://www.khronos.org/opengl/wiki/Vertex_Specification#Vertex_Array_Object)的方式类似。一个对象拥有(我的意思是处理分配)实际顶点,而其他对象通过id引用它们。 – CoryKramer

+1

您可能想要在'Solid'和'Face'中保存'shared_ptr '。除非'Solid'是最终的拥有者,否则你可能需要'Face'中的'weak_ptr'。 – AndyG

回答

0

有管理这些种种关系的许多方面,但如果你想要效率,要边之间共享顶点和共享面之间的边缘那么我建议你应该Solid自己的VertexEdges的完整列表。

然后Edge对其顶点具有某种非拥有的引用,并且Face对其边缘具有某种非拥有的引用。那些非拥有的引用可能像一个指针,但是你必须小心,不要通过重新分配顶点或边的主要列表来使这些指针无效。如果您存储索引,则更安全。但是,这并不意味着你必须参考Solid找出一个顶点/边指数是指:

class Solid { 
    std::vector<Vertex> vertices; 
    std::vector<Edge> edges; 
    std::vector<Face> faces; 

public: 
    Solid(std::vector<Vertex> vertices) : vertices(std::move(vertices)) {} 

    void addEdge(int vertex_index1, int vertex_index2) { 
    edges.emplace_back(vertex_index1, vertex_index2); 
    } 
    void addFace(std::vector<int> edge_indices) { 
    faces.emplace_back(std::move(edge_indices)); 
    } 
    const Vertex &getVertex(int vertex_index) const { return vertices[vertex_index]; } 
    const Edge &getEdge(int edge_index) const { return edges[edge_index]; } 
}; 

class Edge { 
    int vertex_first; 
    int vertex_second; 

public: 
    Edge(int vertex_first, int vertex_second) 
     : vertex_first(vertex_first), vertex_second(vertex_second) {} 

    const Vertex &getVertexFirst(const Solid &solid) const { 
    return solid.getVertex(vertex_first); 
    } 
    const Vertex &getVertexSecond(const Solid &solid) const { 
    return solid.getVertex(vertex_second); 
    } 
}; 

class Face { 
    std::vector<int> edge_indices; 

    int getEdgeIndex(int face_edge_index) const { 
    return edge_indices[face_edge_index]; 
    } 

public: 
    Face(std::vector<int> edge_indices) : edge_indices(std::move(edge_indices)) {} 

    const Edge &getEdge(int face_edge_index, const Solid &solid) const { 
    return solid.getEdge(getEdgeIndex(face_edge_index)); 
    } 
}; 

Live demo

另一种方法是将std::shared_ptr用于EdgeVertex,但您必须为动态内存分配和较差的数据局部性付费。

为了更好地封装,在FaceEdge之内存储对Solid的反向引用是很诱人的。你可以这样做,但vectorFaceEdge有效地包含很多重复的指针。如果这种封装对你很重要,我建议你创建一些封装类来处理包含原始边缘/面对象的边和面,并且还要对Solid进行反向引用。