大話重構連載19:大物件的演化過程
很好,我們終於邁出了重構的第一步,而這第一步我們瞄準了程式碼問題的重災區——超級大函式。超級大函式之所以是程式碼問題的重災區,就是因為它們往往難於閱讀、難於維護。面對大函式我們採取的辦法是拆分,以功能為核心將其拆分成一個一個獨立的函式。拆分後的程式變得易於閱讀了,因為要讀懂程式你不再需要讀完所有程式碼,選擇性的讀取那些頂級函式,只需了了數行程式碼,你就可以明白整個程式。
但是,當我們將數千行的大函式分解成數十個小函式時,另一個問題出現了。想象一下,數十個函式被雜亂無章地堆放在一個物件中,看看就讓人頭疼。實際上,我們是不會這樣做的。當我們開始了對大函式的分解時,隨之而來的就是對大物件的分解。大物件,就是指的那些包含數十個甚至上百個方法或者函式,功能無所不包的超級物件。在很多遺留系統中,總有那麼幾個超級物件,系統幾乎所有的功能都在它的裡面有對應方法。這樣的物件,密密麻麻的方法讓人困惑,更關鍵的是,各種各樣的功能被耦合在一起,稍有修改就會影響到許多功能,甚至讓那些毫不相干的功能產生BUG。因此,我們應當合理地拆分我們的大物件。
與大函式一樣,很多時候遺留系統中的大物件,也都是伴隨系統業務複雜度的逐漸增長而出現的,我們來看看它的演進過程吧。我們說軟體實際上是對現實世界的模擬,通過這種模擬,實現資訊化的管理,來提高我們的生產效率。但是,現實世界是複雜的,各種事物之間存在著各種各樣紛繁複雜的聯絡,因此我們不可能完全模擬現實世界的所有,只可能是現實世界的一部分,客戶急需要模擬的那一部分。
人的大腦認識事物總是一個由簡單到複雜的過程,這是我們的客觀規律。因此,我們的軟體模擬真實世界也是一個由簡單到複雜的過程。最開初我們的想法總是非常簡單而單純的,就是讓軟體做一件非常簡單而明確的事情。由於這時候業務非常簡單,我們不需要太多的類和方法就可以實現業務操作。比如開票業務,就是將已開具的發票資訊讀取出來,儲存。這樣一個簡單操作,設計成一個簡單的開票業務類合情合理。
但是,隨著軟體模擬真實世界的不斷髮展,業務變得越來越複雜。比如這個開票業務,我們隨後的業務開始變更,要檢查購方是否存在、開票人是否有許可權、庫存中是否還有發票,等等。起初只有一種開票方式,但隨著非正常開票業務的增加,許多相關的業務也隨之變化……隨著業務的不斷增加,軟體程式碼的規模也在發生著質的變化(如圖6.1所示)。
圖6.1 開票業務的演化過程
過去開票業務類只有百來行程式碼,現在被膨脹到數千行程式碼。各種條件語句層層巢狀,各種臨時變數穿插跑位,程式變得難於理解。由於讀不懂程式碼,修改程式碼的程式設計師開始在走鋼絲,一不小心改動了某個關鍵程式就可能引入重大BUG。為了避免重大BUG的出現,測試人員耗費巨大精力進行嚴格的測試。毫無疑問,軟體開始進入一種惡性迴圈,軟體退化開始一步步加深。
面對這種軟體規模增大而帶來的惡性迴圈,我們必須做出改變。面對問題我們不能病急亂投醫,而是應當對症下藥。這個正確的藥方就是以職責驅動設計思想為核心,調整我們的程式結構,構建高內聚、低耦合的軟體系統。職責驅動設計,就是要求我們設計的所有類和介面,都要有自己的職責定義。而每個類和介面內部的所有方法和屬性都是圍繞著該職責來進行的,它們都是高度相關的。每個類和介面決不去做跟自己職責無關的事情,所有與自己職責無關的事情,都應當交給其它擁有該職責的類來完成,而自己僅僅是去呼叫。這就是職責驅動設計的思想,而每個類其內部包含的功能所達到的高度相關的程度,我們稱之為“內聚”。
概念似乎有一些抽象,我們來舉例說明吧。對於開票業務,我們設計了開票業務類來處理它,因此開票業務類的職責就是完成開票操作,這似乎毫無問題。但是,我們仔細審視開票操作,就會發現它包含了好幾個部分:首先,我們讀取客戶、開票人、發票庫存等資訊進行相關的校驗,然後儲存這些發票到資料庫中,最後統計當月的票量及金額。通過這樣的分析,它們似乎不再那麼功能相關了,讀取和校驗客戶、開票人、發票庫存等資訊是客戶、開票人、發票庫存實體類的職責,讀取和儲存發票似乎是發票類的職責,而統計當月票量與金額似乎是財會統計類的職責。分與不分,完全取決於軟體程式碼的複雜程度。如果總共也就幾十行程式碼,我們寫成一個類中的幾個方法就可以了;但隨著功能複雜度的加深,那麼我們必須得拆分,分配到不同的類中配合完成我們的功能。
隨著軟體業務的不斷變化,我們的軟體在發生著質的變化。發票儲存前我們必須要進行一系列的校驗工作:檢查購方是否存在、開票人是否有許可權、是否還有發票庫存,等等。不同的校驗,讀取的是不同的資料,它們的順序可能變化,校驗的個數也可能在調整。隨著需求的變化,一些校驗被增加進來而另一些則被剔除。我們判斷功能是否相關的一個非常重要的原則,就是是否是軟體變更的同一個原因。比如,“檢查購方是否存在”與“開票人是否有許可權”,不是軟體變更的同一個原因:“檢查購方是否存在”是與客戶資訊管理直接相關,而“開票人是否有許可權”則是與使用者許可權定義密切相關,因此它們不能放在同一個類中。為什麼呢?因為“檢查購方是否存在”的業務邏輯變更時,不應當影響到“檢查開票人是否有許可權”的功能。最好的辦法就是,將它們各自封裝在各種相關的業務類中(如圖6.2所示)。
圖6.2 開票業務的拆分
經過以上分析我們發現,開票操作隨著業務邏輯的不斷髮展,應當在原有的程式結構上,將開票業務類拆分成幾個部分:各種校驗類、發票業務類與財會統計類。這樣的拆分使得開票業務類最終由一個什麼都乾的多面手,變成了一個管理者。它不再參與那些具體的工作,而是將工作分配給不同的人,成為一個組織協調者。經過這樣的調整,我們的程式將變得更加易於閱讀、維護、變更。
特別說明:希望網友們在轉載本文時,應當註明作者或出處,以示對作者的尊重,謝謝!
相關推薦
大話重構連載19:大物件的演化過程
很好,我們終於邁出了重構的第一步,而這第一步我們瞄準了程式碼問題的重災區——超級大函式。超級大函式之所以是程式碼問題的重災區,就是因為它們往往難於閱讀、難於維護。面對大函式我們採取的辦法是拆分,以功能為核心將其拆分成一個一個獨立的函式。拆分後的程式變得易於閱讀了,因為要讀懂程式你不再需要讀完所有程式碼,選擇性
大話重構連載10:小設計而不是大布局
開車的朋友一定深有體會,駕駛汽車其實就是在不斷矯正汽車行駛方向的一個過程。在整個駕駛過程中,你必須全神貫注地緊盯前方,通過方向盤不斷矯正方向,否則即使行駛在直線路段也可能偏離車道。那些疲勞駕駛的司機,因為進入睡眠狀態,無法再矯正方向,車輛就會越來越偏離航向。這種情況下,即使數秒鐘的小盹,也能造成車毀人亡的嚴重
大話重構連載16:超級大函式
事情總是這樣的:當我們對一個遺留系統一忍再忍,再忍,忍,還要忍……終於積攢到某一天,實在忍無可忍了,拍案而起,不能再忍了,重構!!!事情就這樣發生了。然而,在這時你突然發現,重構的工作千頭萬緒,真不知從何開始。堆積如山的問題此起彼伏,期望修改的設計思緒萬千。這裡有個想法,那裡有個思路,什麼都想做,卻什麼都做不
大話重構連載13:自動化測試——想說愛你不容易
正如許多事情都有其兩面性一樣,測試方法也是這樣。要保證測試方法正確,最簡單、最直觀地想法就是多寫些測試用例,從更多地角度去測試,但這必然增加我們的測試成本。小步快跑要求我們頻繁進行測試,假如我們重構的週期是20分鐘,但測試卻要花掉10分鐘,那麼這樣的成本就實在太大了。假如這種測試還是開發人員手工測試,每天都有
大話重構連載12:你不能沒有保險索
通過前面的描述你已經對重構中“小步快跑”的開發模式有了一個清楚的認識。學會和習慣小步快跑的開發模式,對於重構工作極其重要,因為它讓這種大範圍、大幅度修改程式碼的重構工作變得不再像以往那樣讓人膽戰心驚。究其原因,雖然從結果上是在大範圍、大幅度調整,但每一步卻是小範圍、小福度調整,並且能保證每一步都是正確的。
大話重構連載首頁
ooo 我們 family 不能 blank 順序 關系 trac 工廠 《大話重構》這本書是我寫的第一本書,從今天起我將通過連載的形式逐漸跟大家分享。 這本書讓你: 告別遊擊隊轉變為正規軍。 遠離劣質代碼走向精妙設計 真正明確專業級的軟件開發是如
連載:面向物件葵花寶典:思想、技巧與實踐(19)
完成了用例之後,需求分析的工作基本上已經完成,接下來我們需要趁熱打鐵,完成另外一個事情:提取功能點!有了用例之後,提取功能可以說是一個水到渠成的事情,基本上只是一個文字工作,我們只需要將用例中那些需要系
oracle對大物件型別操作:blob,clob,nclob
1.基本介紹 Oracle和plsql都支援lob(large object) 型別,用來儲存大數量資料,如影象檔案,聲音檔案等。Oracle 9i realse2支援儲存最大為4g的資料,oracle 10g realse1支援最大8到128萬億位元組的資料儲存,依賴於你的db的block s
工業大資料漫談19:工業大資料資料採集常見的工業協議簡介(下)
4、ProfiBus ProfiBus是德國標準(DIN19245)和歐洲標準(EN50170)的現場匯流排標準。由PROFIBUS--DP、PROFIBUS-FMS、PROFIBUS-PA系列組成。DP用於分散外設間高速資料傳輸,適用於加工自動化領域。FMS適用於紡織、樓
連載:面向物件葵花寶典:思想、技巧與實踐(20)
你知道麼,用例圖 不是 用來描述 用例的哦!!!!熟悉UML的朋友都肯定知道,UML有一個叫做用例圖的東東。單純從名字上來看,你可能以為用例圖是用來描述用例的,即:用例圖 = 用例的圖形化表示。然而各位
連載:面向物件葵花寶典:思想、技巧與實踐(39)
又是設計原則,又是設計模式,到底該用哪個呢? =============================================================================在
ISTQB AL-TA/TTA連載系列19:有效選擇測試優先順序
常規的風險評估通過計算可能性和嚴重程度來實現,它的缺點是沒有能夠更具體地體現各種不同因素對風險可能性和嚴重程度的影響。如果在評估風險時考慮風險可能性和嚴重程度的影響因素,我們就可以優化風險評估公式,從而更好構建測試優先順序 風險的可能性和嚴重程度都會受到各種因素的影響。例如
連載:面向物件葵花寶典:思想、技巧與實踐(34)
DIP,dependency inversion principle,中文翻譯為“依賴倒置原則”。DIP是大名鼎鼎的Martin大師提出來的,他在1996 5月的C++ Reporter發表“ The
連載:面向物件葵花寶典:思想、技巧與實踐(21)
用例圖是用來描述系統的,而SSD(系統序列圖)又是來描述用例的,oh my god,這不是在玩我們麼?System Sequence Diagram,縮寫為SSD(注意不要與SSD硬碟混淆),中文翻譯為
連載:面向物件葵花寶典:思想、技巧與實踐(29)
高內聚低耦合,可以說是每個程式猿,甚至是編過程式,或者僅僅只是在大學裡面學過計算機,都知道的一個簡單的設計原則。雖然如此流行和人所眾知,但其實真正理解的人並不多,很多時候都是人云亦云。=========
連載:面向物件葵花寶典:思想、技巧與實踐(27)
類模型指導我們如何宣告類,動態模型指導我們如何實現類!動態模型設計一般都是在類模型設計完成後才開始,因為動態模型設計的時候一般都需要用到類模型中的類。相對類模型來說,動態模型要相對簡單一些,主要原因在於
連載:面向物件葵花寶典:思想、技巧與實踐(18)
很多人在分析需求的時候,採用的是東扯葫蘆西扯瓢的方式,列出了很多的需求點,但當你看完後,你還是不知道到底要幹嘛!! ---- 寫在前面用例,英文名稱Use Case,英文和中文都是很好理解,因為大家都
Cg入門19:Fragment shader - 片段級模型動態變色
tin ogr 沒有 動態 erp unity data pro targe y值要表示範圍為[-0.5,0.5],所以語義要註意不要用Color(註意:Color 語義值範圍為[0,1] )(特別註意:內建的cube範圍才是【-0.5,0.5】,其它模型就不一定是這個值
19:python中的判斷語句
python 數據分析 ubuntu linux 人工智能 機器學習19.1 求三角形的面積問題描述: 給出三角形的三條邊,求其面積。提示: Python的開根號函數sqrt。 你需要判斷三
重構改善既有代碼設計--重構手法02:Inline Method (內聯函數)& 03: Inline Temp(內聯臨時變量)
臨時變量 替代 xtra 移動 get replace 16px ber ble Inline Method (內聯函數) 一個函數調用的本體與名稱同樣清楚易懂。在函數調用點插入函數體,然後移除該函數。 int GetRating()