构建C ++类层次结构以实现可维护性和封装

时间:2011-08-10 20:50:07

标签: c++ data-structures coding-style encapsulation

我对封装有一些一般性问题,因为它与可维护性有关。这是我用来帮助构建解析树的示例类。 (为了教育,我避免使用STL。)

Node类描述树中的节点。管理类ParseTree(未显示)负责以有意义的树状方式构建和维护Node个对象的集合。

// contents of node.h, not including header guard or namespace
class Token;
class Node {
public:
  static const Node* FindParent(const Node* p_root, const Node* p_node);
  static int Height(const Node* p_root);
  static void Print(const Node* p_root);
  Node(const Token * p_tok=0) : p_left_(0), p_right_(0), p_tok_(p_tok) {}
  ~Node() { delete p_left_; delete p_right_; }
  const Node* p_left(void) const { return p_left_; }
  const Node* p_right(void) const { return p_right_; }
  const Token* p_tok(void) const { return p_tok_; }
private:
  friend class ParseTree;
  Node* p_left_;
  Node* p_right_;
  Token* p_tok_;
};

以下四个主题与封装有关。

  1. Node类中的静态方法被声明为静态,因为它们可以在不使用任何私有成员的情况下进行措辞。我想知道他们是否应该在Node之外的公共名称空间中生活,或者作为ParseTree中的静态成员。我的决定应该由ParseTree负责树木的事实来支配,并且按照这种逻辑,这些功能应该存在于ParseTree中吗?

  2. 在相关的说明中,静态方法位于Node而不是ParseTree的原因是因为ParseTree填满了大量成员。我已经读过,保持小而灵活的类对于可维护性更好。我是否应该不遗余力地找到不依赖于私有成员访问的方法,并将它们从我的类定义中拉出来,并将它们放入与类相同的命名空间中分组的函数中?

  3. 我还阅读了一些有关避免私有成员上的mutators的建议,因为它往往会破坏封装,所以我最终只有访问器,让ParseTree使用{{1}的友谊来处理任何修改}}。这真的比变异人更好,只是结束与Node的友谊吗?如果我添加mutators,那么ParseTree可以在其他上下文中重用,而不会添加其他友谊。

  4. 如果我添加mutators并从Node中删除静态函数,我觉得我可以公开数据成员并删除所有访问者/ mutators / friend声明。我的印象是这种方法形式不好。如果我为每个私人会员配备了访问者/变种对,我是否应该对我的设计持怀疑态度?

  5. 如果我的方法中有任何其他明显和错误的东西我没想到要问,我会很感激听到它。

2 个答案:

答案 0 :(得分:1)

我认为 Node 对这些访问者来说太拥挤了,这显然只是暴露私人成员的间接方式。我认为将这些静态成员删除到应用程序命名空间会更清晰。例如:

namespace mycompiler {
    class Node {
        ...
    };

    class ParseTree {
        ...
    };

    const Node* FindParent(...);
    int Height(...);
    void Print(...);
}

通过这种方式,您仍然可以避免污染全局命名空间,但同时保持Node和ParseTree类更小。您还可以重载某些mycompiler::函数(例如Print())以接受命名空间中的任何对象,如果您不想将它们粘贴到您的类中。这将使Node和ParseTree成为更智能的容器,而某些外部逻辑(相关类)可以在mycompiler::中隔离。

答案 1 :(得分:1)

问问自己,什么是节点?显然,这可能是一个父母,一个左孩子和一个正确的孩子。它还包含指向某些数据的指针。节点是否有高度?这取决于上下文,您的节点是否可能在某个时刻成为循环的一部分? ParseTree有一个高度概念,它似乎不是一个节点。

老实说,我建议你首先让你的程序逻辑正确,然后你可以担心OO的花里胡哨。 你提出的问题可能会在你继续进行时回答。