假设我有三个类,Solid
、Face
和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
的"超集"。Solid
管理的每个Face
都将具有Solid.edges
的"子集"。此外,任何两个Solid.faces
都可以具有共同的Edge
。
我的问题是:是否有任何设计模式或一般面向对象原则来处理这种情况?如何管理Solid.edges
和Face.edges
之间的关系?更具体地说
有很多方法可以管理这些类型的关系,但是如果您想要效率并且想要在边之间共享顶点并在面之间共享边,那么我建议您的Solid
应该拥有完整的Vertex
和Edges
列表。
然后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));
}
};
现场演示。
另一种方法是将std::shared_ptr
用于Edge
和Vertex
但随后您必须为动态内存分配和较差的数据局部性付费。
在Face
内部存储对Solid
的反向引用是很诱人的,Edge
以便更好地封装。你可以这样做,但Face
和Edge
vector
有效地包含大量重复的指针。如果这种封装对您很重要,我建议您创建某种包装类来处理包含原始边缘/面对象的边缘和面以及对Solid
的反向引用。