Is there a design pattern or basic object oriented principle that addresses this case of shared resources?
For example, I have three classes Solid
, Face
and Edge
that should be defined as:
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;
}
in this example Solid
manages a "superset" of Edge
s. Each Face
that manages Solid
will have a "subset" Solid.edges
. Also, any two Solid.faces
can share a common Edge
.
My question is, are there any design patterns or general object-oriented principles to deal with situations like this? How can I manage the relationship between Solid.edges
and Face.edges
? More specific
source to share
There are many ways to manage these types of relationships, but if you want to be more efficient and want to share vertices between edges and swap edges between faces, I suggest yours Solid
have a complete list of Vertex
and Edges
.
Then Edge
has some link not related to its vertices, and Face
has some link to unrelated edges. These non-owner references can be something like a pointer, but then you need to be careful not to invalidate these pointers by reallocating the main vertex or edge list. It's safer if you store indexes instead. But that means you need to refer to Solid
to find out what the vertex / edge index refers to:
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));
}
};
An alternative is to use std::shared_ptr
for Edge
and Vertex
, but then you have to pay for heap allocation and lower data locality.
It's tempting to keep the back reference Solid
inside Face
and Edge
for better encapsulation. You could do this, but then vector
out Face
and Edge
effectively contain a lot of duplicate pointers. If this kind of encapsulation is important to you, I suggest you create some kind of wrapper classes for working with edges and faces that contain a raw edge / face object, as well as a back reference to Solid
.
source to share