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

+3


source to share


1 answer


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));
  }
};

      



Live demo .

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

.

0


source







All Articles