Java程式設計師應瞭解的10個物件導向設計原則

發表於2012-03-13

英文原文:javarevisited.blogspot.comw,翻譯:iteye

物件導向設計原則是 OOPS(Object-Oriented Programming System,物件導向的程式設計系統)程式設計的核心,但大多數 Java 程式設計師追逐像 Singleton、Decorator、Observer 這樣的設計模式,而不重視物件導向的分析和設計。甚至還有經驗豐富的 Java 程式設計師沒有聽說過 OOPS 和 SOLID設計原則,他們根本不知道設計原則的好處,也不知道如何依照這些原則來進行程式設計。

眾所周知,Java 程式設計最基本的原則就是要追求高內聚和低耦合的解決方案和程式碼模組設計。檢視 Apache 和 Sun 的開放原始碼能幫助你發現其他 Java 設計原則在這些程式碼中的實際運用。Java Development Kit 則遵循以下模式:BorderFactory 類中的工廠模式、Runtime 類中的單件模式。你可以通過 Joshua Bloch 的《Effective Java》一書來了解更多資訊。我個人偏向的另一種物件導向的設計模式是 Kathy Sierra 的 《Head First設計模式》 以及 《Head First Object Oriented Analysis and Design》

雖然實際案例是學習設計原則或模式的最佳途徑,但通過本文的介紹,沒有接觸過這些原則或還在學習階段的 Java 程式設計師也能夠了解這 10 個物件導向的設計原則。其實每條原則都需要大量的篇幅才能講清楚,但我會盡力做到言簡意賅。

原則1:DRY(Don’t repeat yourself)

即不要寫重複的程式碼,而是用“abstraction”類來抽象公有的東西。如果你需要多次用到一個硬編碼值,那麼可以設為公共常量;如果你要 在兩個以上的地方使用一個程式碼塊,那麼可以將它設為一個獨立的方法。SOLID 設計原則的優點是易於維護,但要注意,不要濫用,duplicate 不是針對程式碼,而是針對功能。這意味著,即使用公共程式碼來驗證 OrderID 和 SSN,二者也不會是相同的。使用公共程式碼來實現兩個不同的功能,其實就是近似地把這兩個功能永遠捆綁到了一起,如果 OrderID 改變了其格式,SSN 驗證程式碼也會中斷。因此要慎用這種組合,不要隨意捆綁類似但不相關的功能。

原則2:封裝變化

在軟體領域中唯一不變的就是“Change”,因此封裝你認為或猜測未來將發生變化的程式碼。OOPS 設計模式的優點在於易於測試和維護封轉的程式碼。如果你使用 Java 編碼,可以預設私有化變數和方法,並逐步增加訪問許可權,比如從 private 到 protected 和 not public。有幾種 Java 設計模式也使用封裝,比如 Factory 設計模式是封裝“物件建立”,其靈活性使得之後引進新程式碼不會對現有的程式碼造成影響。

原則3:開閉原則

即對擴充套件開放,對修改關閉。這是另一種非常棒的設計原則,可以防止其他人更改已經測試好的程式碼。理論上,可以在不修改原有的模組的基礎上,擴充套件功能。這也是開閉原則的宗旨。

原則4:單一職責原則

類被修改的機率很大,因此應該專注於單一的功能。如果你把多個功能放在同一個類中,功能之間就形成了關聯,改變其中一個功能,有可能中止另一個功能,這時就需要新一輪的測試來避免可能出現的問題。

原則5:依賴注入或倒置原則

這個設計原則的亮點在於任何被 DI 框架注入的類很容易用 mock 物件進行測試和維護,因為物件建立程式碼集中在框架中,客戶端程式碼也不混亂。有很多方式可以實現依賴倒置,比如像 AspectJ 等的 AOP(Aspect Oriented programming)框架使用的位元組碼技術,或 Spring 框架使用的代理等。

原則6:優先利用組合而非繼承

如果可能的話,優先利用組合而不是繼承。一些人可能會質疑,但我發現,組合比繼承靈活得多。組合允許在執行期間通過設定類的屬性來改變類的行為,也可以通過使用介面來組合一個類,它提供了更高的靈活性,並可以隨時實現。《Effective Java》也推薦此原則。

原則7:里氏代換原則(LSP)

根據該原則,子類必須能夠替換掉它們的基類,也就是說使用基類的方法或函式能夠順利地引用子類物件。LSP 原則與單一職責原則和介面分離原則密切相關,如果一個類比子類具備更多功能,很有可能某些功能會失效,這就違反了 LSP 原則。為了遵循該設計原則,派生類或子類必須增強功能。

原則8:介面分離原則

採用多個與特定客戶類有關的介面比採用一個通用的涵蓋多個業務方法的介面要好。設計介面很棘手,因為一旦釋放介面,你就無法在不中斷執行的情況 下改變它。在 Java 中,該原則的另一個優勢在於,在任何類使用介面之前,介面不利於實現所有的方法,所以單一的功能意味著更少的實現方法。

原則9:針對介面程式設計,而不是針對實現程式設計

該原則可以使程式碼更加靈活,以便可以在任何介面實現中使用。因此,在 Java 中最好使用變數介面型別、方法返回型別、方法引數型別等。《Effective Java》 和《Head First Design Pattern》書中也有提到。

原則 10:委託原則

該原則最典型的例子是 Java 中的 equals () 和 hashCode () 方法。為了平等地比較兩個物件,我們用類本身而不是客戶端類來做比較。這個設計原則的好處是沒有重複的程式碼,而且很容易對其進行修改。

總之,希望這些物件導向的設計原則能幫助你寫出更靈活更好的程式碼。理論是第一步,更重要的是需要開發者在實踐中去運用和體會。

 

相關文章