在面向對象編程時對於類的劃分有哪些心得?
01-06
有時候一些東西可以寫成一個類也可以多個類,如何兼顧各種約束,找到一個合適的平衡點?
例如Python自有的cgi.escape和HTMLParser.HTMLParser,混入帕斯卡命名法不說,將這兩個功能這樣封裝是出於何種考慮?
以容易寫unittest又絕對不會破壞封裝為準
首先是方法學:
- 基於用例分析(Use case Analysis)的方法
- 基於CRC方法(Class Responsibility Collaborator)
- 抽象原則
- 遵循高內聚,低耦合的原則
- 遵循SOLID 原則特別是開閉原則(Open/closed principle)和單一責任原則(Single responsibility principle)
最後,持續進行重構
如果針對實體的話,按照面向對象對類的定義,一組相同特性的對象可以歸一個類就算一個類,如果多個類共用一組屬性的,將共用屬性組歸為一個繼承類,然後具體類繼承為子類再實現差異。
如果能全部歸一類又可以分多類,應該沒處理好公共屬性。經驗之談。
前期的需求分析的時候,把需求、功能劃分細緻一點。然後,把要做的功能分幾堆。某一堆功能專註做某一類事情,比如資料庫讀,資料庫寫,介面交互,數據計算等。
你看,天然的不就出來「類」這個東西了么。設計的時候,重點注意兩個方面。
第一,介面必須隔離。SOLID里提到了單一職責、介面隔離兩個原則。單一職責確實很難,有時候打破它的性價比更高。但介面隔離一定要做到。介面不隔離,就不可能單一職責,就很難遵守開閉、里氏等原則。第二,考慮開閉原則。開閉原則是一切軟體設計的核心思想。但是要嚴格做到真的太難了。首先沒人能在剛開始的時候就考慮到所有以後可能的變化;其次即使考慮到了,實現起來的成本也會居高不下。所以,在可以接受的工作量範圍內,以你和業務、需求方的經驗來做一些開閉的設計就行。開發的時候,主要靠經驗和技巧來做一些重構。
這裡可以提一點,就是有些看起來很無聊的代碼規範有時候真的很有幫助。比如一個方法不能超過30行,一個類不能超過300行這種。當行數超過規範的時候,你自然就會想重構、拆分子類。另外 @vczh 說到了以unittest為準,這也是一個很好的思路,尤其是在tdd實踐中。這個問題必須要分開討論。
對於需求變化不頻繁的,當然是以test是否方便為依據。
至於需求變化頻繁的,相信我,只要能跑就行。
所以我從來都是儘可能不幹業務邏輯層的活,我向來是努力寫核心功能。舉例來說,對於典型的後端mvc的項目,我一般主要寫m,頂多寫一點m和c之間的介面。但是c和v的主要部分我一點都不想動。這個時候,我寫完我的介面就可以好好以test為依據寫類了。純靠感覺...
This is why we need design patterns. You may want to refer to GoF("Design Patterns: Elements of Reusable Object-Oriented Software").=============================好吧我沒啥寫大型項目的經驗,還是看以上各位答主答的吧。
SOLID(單一功能、開閉原則、里氏替換、介面隔離以及依賴反轉)
根據業務吧,如果從面相對象的思路去思考,無非是把概念進行封裝,
概念可以分為物件,
行為和狀態,當然,還有一些是自己認為它是一個完整的概念,也可以劃分出去,單獨描繪,有點像畫畫。類要封裝變化。把容易根據需求變化的地方封裝起來,這也對應設計模式的開閉原則(對派生開放,對修改封閉)
推薦閱讀:
※arraylist和array在內存分配和調用、編譯上有什麼本質區別?
※c++為什麼要讓struct可以定義成員函數?
※如何把思維從面向過程轉向面向對象?
※C++通過基類指針delete派生類數組,析構函數是虛函數,程序為什麼會崩潰?