У меня есть несколько общих вопросов об инкапсуляции, связанной с ремонтопригодностью. Вот пример класса, который я использовал для помощи в построении дерева синтаксического анализа. (Я избегал 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_;
};
Следующие четыре темы относятся к инкапсуляции.
Статические методы в классе
Node
объявлены статическими, потому что их можно сформулировать без использования каких-либо закрытых членов. Мне интересно, должны ли они жить внеNode
в общем пространстве имен или, может быть, как статические члены вParseTree
. Должно ли мое решение зависеть от того факта, чтоParseTree
отвечает за деревья, и по этой логике функции должны находиться вParseTree
?В связи с этим, причина, по которой статические методы находятся в
Node
вместоParseTree
, заключалась в том, чтоParseTree
заполнялся большим количеством членов. Я читал, что небольшой размер класса и маневренность лучше для ремонтопригодности. Должен ли я изо всех сил искать методы, которые не полагаются на доступ к частным членам, и вытаскивать их из определения моего класса и помещать их в функции, сгруппированные в том же пространстве имен, что и класс?Я также читал несколько советов по тому, как избегать мутаторов для частных членов, поскольку они имеют тенденцию нарушать инкапсуляцию, поэтому в итоге у меня остались только аксессоры, и я позволил
ParseTree
обрабатывать любые модификации, используя его дружбу сNode
. Неужели это лучше, чем иметь мутаторы и просто прекратить дружбу сParseTree
? Если я добавлю мутаторы, тоNode
можно будет повторно использовать в других контекстах без добавления еще одной дружбы.Если я добавлю мутаторы и удалю статические функции из
Node
, я чувствую, что могу просто сделать члены данных общедоступными и удалить все объявления аксессоров / мутаторов / друзей. У меня сложилось впечатление, что такой подход был бы дурным тоном. Следует ли мне скептически относиться к своему дизайну, если у меня есть пары аксессуаров / мутаторов для каждого закрытого члена?Если в моем подходе есть еще что-то очевидное и неправильное, о чем я не подумал бы спросить, я был бы признателен, если бы об этом услышал.