2011-08-10 74 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_; 
}; 

以下四個主題與封裝有關。

  1. Node類的靜態方法聲明爲靜態的,因爲它們可以在不使用任何私有成員來表述。我想知道他們是否應該在Node以外的公共命名空間中生存,或者可能是ParseTree以內的靜態成員。如果我的決定被ParseTree負責樹木的事實所支配,並且通過該邏輯,函數應該存在於ParseTree

  2. 在相關說明中,靜態方法在Node而不是ParseTree的原因是因爲ParseTree已填滿了大量成員。我已經讀過,保持小班和敏捷更適合可維護性。我是否應該去尋找不依賴私人成員訪問的方法,並將它們從我的類定義中提取出來,並將它們放入與類相同的名稱空間中分組的函數中?

  3. 我還曾讀到避免對私有成員的存取器,因爲它往往會破壞封裝一些建議,所以我最終只具有存取,讓ParseTree使用帶有Node的友誼處理任何修改。這真的比擁有變種者更好,只是結束與ParseTree的友誼?如果我添加mutators,那麼Node可以在其他上下文中重用,而不會增加另一種友誼。

  4. 如果我添加mutators並從Node中刪除靜態函數,我覺得我可以公開數據成員,並刪除所有訪問器/ mutators/friend聲明。我有這樣的印象,這種做法是不好的形式。我應該對我的設計持懷疑態度,如果我對每個私人成員都有訪問器/增變器對?

  5. 如果還有什麼其他明顯和錯誤的方法,我不認爲問,我會很感激聽到它。

+1

你的論點是圍繞着圈子發生的,當我想到這些問題時,就會發生在我身上。我不會太擔心,你看起來像你知道你在做什麼。但非常快1)我不認爲他們應該在節點。 2)是,全球職能。 3)在重用Node方面,我看不出有什麼優勢,它不像有任何重要的價值,將它與ParseTree綁定在一起。 4)不,因爲像Node這樣簡單的事情,一切公開都是可能的。 – john

+0

'Mutator',耶穌安士特和吸氣者有什麼問題? – James

+0

我在過去幾年中大部分時間都在做低層次的工作(IC設計,hdl,嵌入式C)。當我向我描述面向對象的設計時,我的一位密友一直用它來指代訪問者和變種者,當我想到與私人成員進行交互的公共成員函數時,這就是我的頭腦。 –

回答

1

問問自己,什麼是節點?顯然,這可能是一個父母,一個左邊的孩子和一個正確的孩子。它還包含一些指向某些數據的指針。節點有高度嗎?這取決於上下文,你的節點有可能在某個時間點是循環的一部分嗎?一個ParseTree有一個高度的概念,它似乎並不是一個節點。

說實話,我建議你先讓你的程序邏輯正確,然後你可以擔心OO鈴聲和口哨聲。 您提出的問題可能會在您繼續時回答自己。

+0

謝謝,你問的問題讓我失望了一個有用的思路。 這就是說,我完成了我的程序,但我覺得我的組織並不合適。而且我還沒有一個完善的直覺或一套問題,我可以問自己組織我的代碼。另外,我還沒有看到足夠大的問題,看到我的天真設計會損害我的實施。 –

1

我覺得節點是有點太在這些訪問,這顯然是你的私有成員揭露的只是一種間接的方式擁擠。我認爲將這些靜態成員移除到應用程序名稱空間會更清潔一些。例如:

namespace mycompiler { 
    class Node { 
     ... 
    }; 

    class ParseTree { 
     ... 
    }; 

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

這樣,您仍然可以避免污染全局命名空間,但同時保持Node和ParseTree類更小。如果您不想將它們粘貼到您的類中,您也可以重載某些mycompiler::函數(例如Print())以接受來自命名空間的任何對象。這會使Node和ParseTree更智能的容器,而一些外部邏輯(相關類)可以在mycompiler::中隔離。