2011-08-10 26 views
2

カプセル化に関する一般的な質問は、保守性に関するものです。ここでは、解析ツリーの構築を支援するために使用したクラスの例を示します。 (私は教育のためにSTLを避けました)メンテナンスとカプセル化のためのC++クラスの階層構造

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

次の4つのトピックは、カプセル化に関連しています。彼らは任意のプライベートメンバーを使用せずに言うこともできるので、Nodeクラスの

  1. 静的メソッドは、静的に宣言されています。私は彼らが共通の名前空間にNodeの外に住んでいなければならないのか、あるいはParseTreeの中の静的なメンバーとして住んでいるのだろうと思います。私の決定は、ParseTreeが木を担当しているという事実によって支配されるべきであり、その論理によって関数はParseTreeに生きるべきですか?

  2. 関連するメモでは、ParseTreeの代わりに、静的メソッドがNodeである理由は、ParseTreeが多数のメンバーでいっぱいだったためです。私は、クラスを小さく保ち、敏捷性が保守性に優れていると読んでいます。プライベートメンバーのアクセスに依存しないメソッドを見つけ出し、それらをクラス定義から取り除き、それらをクラスと同じ名前空間内にグループ化された関数に入れる方法はありませんか?

  3. 私はまた、カプセル化を破る傾向があるので、プライベートメンバーにミューテータを避けに関するいくつかのアドバイスを読んでいたので、私は唯一のアクセサを持つことになった、とParseTreeNodeとの友情を使って任意の変更を処理してみましょう。これは実際に突然変異を持っているだけでなく、ParseTreeで友情を終わらせるよりも本当に良いですか?ミューテータを追加すると、Nodeは別のフレンドシップを追加せずに他のコンテキストで再利用できます。

  4. Nodeからミューテータを追加して静的関数を削除すると、データメンバーをパブリックにして、すべてのアクセサ/ミューテータ/フレンド宣言を削除できたようです。私はそのようなアプローチが悪い形であるという印象を持っています。プライベートメンバーごとにアクセサー/ミューテータのペアがある場合は、私のデザインに懐疑的なはずですか?

  5. 私のアプローチについて他に何か尋ねると思わなかったことがあれば、それについて聞いていただければ幸いです。

+1

あなたの議論は円で行われています。これは、私がこれらの問題について考えるときに起こることです。私はそれについてあまり心配しないでしょう、あなたはあなたが何をしているかを知っているように見えます。しかし、非常に速く1)私は彼らがノードにあるべきだとは思わない。 2)はい、グローバルな機能です。 3)Nodeを再利用することにはほとんど利点がありません。ParseTreeに結びつけておくと、大きな価値があるとは限りません。 4)いいえ.Nodeと同じくらい簡単なことは、すべてが公開されている可能性があるからです。 – john

+0

「突然変異子」、イエスセッターズとゲッターズの何が間違っていますか? – James

+0

私はここ数年間、低レベルの仕事をしていました(IC設計、hdl、埋め込まれたCのスポット)。私の親しい友人は、オブジェクト指向設計を私に説明したときにアクセサやミューテータを参照するために常に使用しています。だから、プライベートメンバーとやりとりするパブリックメンバー関数について考えるとき、私は頭に入れています。 –

答えて

1

ノードとは何ですか?明らかに、それは親、左の子、そして右の子を持つかもしれないものです。それはまた、いくつかのデータへのポインタを保持します。ノードには高さがありますか?コンテキストに依存しますが、ノードがある時点でサイクルの一部になる可能性がありますか? ParseTreeは高さの概念を持っていますが、それはノードのようには見えません。

正直言って、あなたのプログラムのロジックを正しいものにしてから、オブジェクト指向の鐘や笛を心配することをお勧めします。 あなたの質問はあなたが進むにつれて答えるでしょう。

+0

ありがとう、あなたが聞いている質問は、私にとって有用な考え方を導いてくれます。 私はプログラムを終えましたが、自分の組織が適切であるとは思わなかった。そして、私はまだ自分のコードを整理するために自分自身に尋ねることができるよく発達した直感や一連の質問を持っていません。さらに、私は私の素朴なデザインが私の実装を損なうのに十分な大きさの問題を抱えていません。 –

1

私はノードは明らかにあなたのプライベートメンバーを露出させるだけの間接的な方法であるこれらのアクセサ、と少しも混雑していると思います。私はこれらの静的メンバーをアプリケーションの名前空間に取り除くのが少し面倒だと思います。例:

namespace mycompiler { 
    class Node { 
     ... 
    }; 

    class ParseTree { 
     ... 
    }; 

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

このようにして、グローバル名前空間を汚染することなく、ノードとParseTreeクラスを小さく保つことができます。 mycompiler::の機能(たとえばPrint())の一部をオーバーロードして、名前空間のオブジェクトをクラスに貼り付ける必要がない場合は、受け入れることもできます。これにより、NodeおよびParseTreeはよりインテリジェントなコンテナになりますが、(関連するクラスへの)外部ロジックは、mycompiler::に分離できます。

関連する問題