在面向對象編程時對於類的劃分有哪些心得?

有時候一些東西可以寫成一個類也可以多個類,如何兼顧各種約束,找到一個合適的平衡點?

例如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派生類數組,析構函數是虛函數,程序為什麼會崩潰?

TAG:Python | Java | 面向對象編程 | C | C# |