是否有处理这种共享资源情况的设计模式或基本的面向对象原则?

Posted

技术标签:

【中文标题】是否有处理这种共享资源情况的设计模式或基本的面向对象原则?【英文标题】:Is there a design pattern or basic object-oriented principle that deals with this case of shared resources? 【发布时间】:2018-01-08 09:11:15 【问题描述】:

假设我有三个类,SolidFaceEdge,定义如下:

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 管理 Edges 的“超集”。 Solid 管理的每个Face 将有一个Solid.edges 的“子集”。此外,任意两个Solid.faces 可能有一个共同的Edge

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

【问题讨论】:

通常您只将 Edge 缓冲区存储在 Solid 对象中,并且为每个 Face 存储它所拥有的 Edge 的索引。 (与存储顶点的传统计算机渲染并行绘制) 正如@meowgoesthedog 提到的,这类似于OpenGL 处理Vertex Arrays 的方式。一个对象拥有(我的意思是处理分配)实际顶点,而其他对象通过 id 引用它们。 您可能希望在SolidFace 中保存shared_ptr&lt;Edge&gt;。除非Solid 是最终所有者,否则您可能需要Face 中的weak_ptr 基本类型不应该是点(0D)吗?现在,如果您更改实体的面,它的面可能不再连接。另一方面,如果你的基本对象是点,那么如果你改变一个点,边和面以及实体仍然会连接起来。 @walter,最终,我想将Vertex 添加到此设计中,Solid 也可以访问,但主要由Edge 管理。不过,我想保持示例简单。 【参考方案1】:

有很多方法可以管理这些类型的关系,但是如果您想要提高效率并且想要在边之间共享顶点并在面之间共享边,那么我建议您的Solid 应该拥有Vertex 和@987654324 的完整列表@。

然后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 的反向引用以更好地封装是很诱人的。你可以这样做,但是FaceEdgevector 实际上包含很多重复的指针。如果这种封装对您很重要,我建议您创建某种包装类来处理包含原始边缘/面对象的边缘和面,以及对Solid 的反向引用。

【讨论】:

以上是关于是否有处理这种共享资源情况的设计模式或基本的面向对象原则?的主要内容,如果未能解决你的问题,请参考以下文章

数据库设计原则(转载)

数据库设计中的14个技巧

设计模式——单例模式

Java面向对象程序设计------异常处理(异常*部分)

Java面向对象程序设计------异常处理(异常*部分)

Java面向对象程序设计------异常处理(异常*部分)