標籤:style blog color 使用 ar strong div 問題 sp
前言
作為一名優秀的程式員,必須保證自己的代碼能提供正確的,完善的介面,如此方能和同事,甲方更好的溝通合作,也讓自己的代碼更加地容易維護。
本文將介紹一些設計優秀介面的思路。
思路一:匯入新的類型
下面還是先看這個例子,我定義了一個儲存日期的 Date 類:
1 class Date2 {3 public:4 Date(int month, int day, int year);5 // ......6 };
可用以下方法定義一個 Date 對象:
1 Date d(30, 3, 1995);
可有些使用者會犯很蠢的錯誤,比如:
1 Date d(30, 3, 1995);
顯然,他使用者將介面的參數輸錯位了。然而,優秀的介面應當能夠友好反饋錯誤資訊給使用者,這種情況下,最好的策略就是定義新的類型,請參考下面這個 Date 類的設計:
1 class Day 2 { 3 public: 4 explicit Day(int d) 5 :val(d) {} 6 // ...... 7 private: 8 int val; 9 };10 11 class Month12 {13 public:14 static Month Jan() {15 return Month(1);16 }17 static Month Feb() {18 return Month(2);19 }20 // ......21 22 private:23 explicit Month(int m) {24 val = m;25 }26 // ......27 28 int val;29 // ......30 };31 32 class Year33 {34 public:35 explicit Year(int y)36 :val(y) {}37 private:38 int val;39 };
而定義一個 Date 對象,可採用如下方式:
1 Date d(Month::Feb(), Day(30), Year(1995));
在日,月,年各個類中,還可以實現更進階的封裝。
思路二:引導使用者進行正確編碼
這裡繼續上一篇文章中提到的智能指標的一個例子,這裡要說明的是,當時給出的那個工廠函數:
1 class Investment2 {3 // ......4 };5 6 Investment * createInvestment();
並不是很好的一種設計。
為啥?因為使用者可能忘了使用智能指標把 Investment * 接過去。而使用下面的工廠函數介面設計可以有效避免這個問題:
1 std::tr1::shared_ptr<Investment> createInvestment();
這樣就讓使用者你不用智能指標都不行了,哈哈。
甚至你還可以更過分,指定智能指標在資源被指數為0的時候要調用的解構函式:
1 std::tr1::shared_ptr<Investment> createInvestment() 2 { 3 // 指定智能指標類型及刪除器 4 std::tr1::shared_ptr<Investment>retVal (static_cast<Investment *>(0), getRidOfInvestment); 5 6 // retVal = ... 7 // 令 retVal 指向正確的對象 8 9 return retVal;10 }
上段代碼中的getRidOfInvestment是你自己指定的刪除器。
思路三:限制類型什麼事情可以做什麼事情不能做
使用 const,explicit等限制性關鍵字,屏蔽無用的拷貝建構函式等可以做到這點。
這些在以前的文章中均有講解。
思路四:使你的類盡量表現得像內建類型
要做到這點可不簡單,你需要以"當初語言設計者設計語言內建類型時"那般謹慎的思考class的設計,對設計出的class,我們需要問自己以下幾個問題:
1. 新的對象資源在何時建立? 何時銷毀?
這部分同樣涉及到建構函式,解構函式的編寫。
2. 對象的初始化和賦值應該有什麼樣的差別?
這部分涉及到建構函式,拷貝建構函式,賦值運算子的編寫。不要混淆這兩個概念。
3. 如果對象發生了值傳遞,意味著什嗎?
你得仔細考慮這期間發生的資源相關的一些問題。
4. 哪些對象是合法範疇?
對象的成員是不是合法,這點很重要。它影響到了你諸多成員函數的錯誤檢查工作,也影響到了拋出的異常。
5. 新的類需不需要配合某個繼承圖系?
如果這個類的子類要實現多態,那麼成員函數就得聲明為虛函數;如果這個類繼承自其它類,那麼當你自訂拷貝建構函式或者重載賦值運算子的時候,也得對父類部分做出處理。
6. 什麼樣的操作符和函數對這個新的類型來說是合理的?
需要考慮這個類型應該對哪些運算子多載,還有哪些函數被當做成員函數,哪些用非成員函數實現。
具體的選取規則,以後會有篇文章專門講。
7. 什麼樣的標準函數應當駁回?
將它聲明為 private
8. 新的類型成員將被哪些對象取用?
這個涉及到變數private,protected,以及友元相關機制。
9. 新的類型是否應當滿足一般化的要求?
如果你要定義的是一個類家族,那麼你需要的不止是一個類,而是一個類模板
小結
1. 類的設計不要貪快。要盡量滿足,實現這些規則,貪快會導致開發後期事倍功半。
2. 本文應當在實際項目中進行類設計的時候邊設計邊看,如此,方能有顯著的提高。
為使用者設計良好的介面