本節書摘來自異步社群出版社《c++程式設計規範:101條規則、準則與最佳實踐》一書中的第2章,第2.1節,作者:【加】herb sutter , 【羅】andrei,更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。
c++程式設計規範:101條規則、準則與最佳實踐
複雜性啊,愚人對你視而不見,實幹家受你所累。
有些人避而遠之。惟智者能夠善加消除。
——alan perlis
我知道,但是卻又忘記了hoare的至理名言:不成熟的優化是程式設計中的萬惡之源。
——donald knuth[1]
the errors of tex[knuth89]
完全區分設計風格與編碼風格是非常困難的。我們将一般在實際編寫代碼時才用得到的條款留到下一部分介紹。
本部分集中讨論适用面比一個特定的類或者函數更廣的原則和實踐。比較典型的包括:簡單和清晰之間的平衡(第6條),避免不成熟的優化(第8條),避免不成熟的劣化(第9條)。這三個條款不僅适用于函數編寫的層次,而且适用于類和子產品設計權衡的更大範圍,适用于更深的應用程式架構決策。(它們也适用于所有程式員。如果你不以為然,請重讀上面knuth的話,注意其中的引用部分。)
緊接其後,本部分和下一部分的其他條款讨論的都是依賴性管理的各個方面。依賴性管理是軟體工程的一個基礎,也是貫穿本書不斷出現的主題。停下來,任意選擇一個優秀的軟體工程技術(任何好的技術都行),思考一下。無論選擇哪一個,都将發現,它都是在想盡辦法減少依賴性。繼承?是為了使所編寫的代碼使用不依賴于實際派生類的基類。盡量減少全局變量?是為了減少因可見範圍太大的資料所産生的遠距離依賴。抽象?是為了消除處理概念的代碼和實作它們的代碼之間的依賴。資訊隐藏?是為了使客戶代碼不依賴實體的實作細節。依賴性管理的一個相關問題還反映在避免使用共享狀态(第10條)中,反映在應用資訊隐藏(第11條),以及更多的其他條款中。
本部分中我們選出的最有價值條款是第6條:正确、簡單和清晰第一。因為這些要求真地太必需了。
摘要
一次隻解決一個問題:隻給一個實體(變量、類、函數、名字空間、子產品和庫)賦予一個定義良好的職責。随着實體變大,其職責範圍自然也會擴大,但是職責不應該發散。
讨論
人們常說,好的商業理念能夠一言以敝之。同樣,每個程式實體也應該隻有一個明确的目的。
如果一個實體有幾個不同的目的,那麼其使用難度往往會激增,因為這種實體除了會增加了解難度、複雜性和各部分中的錯誤外,還會導緻其他問題。這種實體不僅更大(常常毫無合理理由),而且更難以使用和維護。此外,這種實體經常會為自身的一些特定用途提供有問題的接口,因為各個功能領域之間的部分重疊,會影響幹淨利落地實作每個功能所需的洞察力。
具有多個不同職責的實體通常都是難于設計和實作的。“多個職責”經常意味着“多重性格”——可能的行為和狀态的各種組合方式。應該選擇目的單一的函數(見第39條),小而且目的單一的類,以及邊界清晰的緊湊子產品。
應該用較小的低層抽象建構更高層次的抽象。要避免将幾個低層抽象集合成一個較大的低層次抽象聚合體。用幾個簡單的行為來實作一個複雜的行為,比反其道而行之更加容易。
示例
例1 realloc。在标準c語言中,realloc是一個臭名昭著的不良設計。這個函數承擔了太多的任務:如果傳入的指針參數為null就配置設定記憶體空間,如果傳入的大小參數為0就釋放記憶體空間,如果可行則就地重新配置設定,如果不行則移到其他地方配置設定。這個函數不易于擴充,普遍認為它是一個目光短淺的失敗設計。
例2 basic_string。在标準c++語言中,std:: basic_string是另一個臭名昭著的不良設計——巨大的類設計。在一個臃腫的類中添加了太多“多多益善”的功能,而這隻是為了試圖成為容器但卻沒有做到,在用疊代還是索引上猶豫不決,還毫無道理地重複了許多标準算法,而為擴充所留的裕度又很小(見第44條的示例)。
參考文獻
[henney02a] ● [henney02b] ● [mcconnell93] §10.5 ● [stroustrup00] §3.8, §4.9.4, §23.4.3.1 ● [sutter00] §10, §12, §19, §23 ● [sutter02] §1 ● [sutter04] §37-40
第條 正确、簡單和清晰第一