Java程序員應該知道的10個面向對象理論
英文原文:10-object-oriented-design-principles
面向對象理論是面向對象編程的核心,但是我發現大部分 Java 程序員熱衷于像單例模式、裝飾者模式或觀察者模式這樣的設計模式,而并沒有十分注意學習面向對象的分析和設計。學習面向編程的基礎(如抽象,封裝,多態,繼承等)是非常重要的,而運用它們來設計干凈的模塊也同樣重要。我也認識很多不同等級的程序員,他們沒有聽過這些面向對象理論,或者不知道某個設計理論有什么好處,或者如何在編碼中使用這些設計理論。
我們起碼要設計出高度一致而且松散耦合的代碼。Apache 和 Sun 的源代碼就是學習 Java 面向對象理論的非常好的例子。JDK 遵循了一些設計模式,譬如在 BorderFactory 中使用工廠模式,Runtime 類中使用單例模式,java.io 中的許多類中使用裝飾者模式。如果你真的對 Java 編程感興趣,請先閱讀 Joshua Bloch 的 Effective Java,正是他參與編寫了 Java API。另外兩本我喜歡的關于設計模式的書還有,Kathy Sierra 等編寫的的 Head First Design Pattern 和 Head First Object Oriented Analysis and Design。這些書幫助理解面向對象理論,并幫助我寫出更好的代碼。
學習任何設計理論或模式最好的方法就是現實世界中的例子,這篇文章只是要給還在學習階段的程序員介紹面相對象理論。我想以下每一條都需要用一篇文章來詳細介紹,我以后也會逐一介紹的,只是現在先來個快速瀏覽一下。
避免重復,DRY (Don’t repeat yourself)
面相對設計理論的第一條就是避免重復,不要寫重復的代碼,盡量將共同的功能放在一個地方。如果你準備在不同地方寫同一段代碼,那么只寫一個方法。如果你不止一次硬編碼某個值,那么將其聲明成 public final 常量。這么做的好處就是容易維護。但是不要濫用這一條,重復不是指代碼的重復,而是指功能的重復。譬如你有一段相同的代碼來驗證 OrderID 和 SSN,但它們代表的意義并不相同。如果你將兩個不同的功能合并在一起,當 OrderID 更改了格式之后,那么檢驗 SSN 的代碼就會失效。所以要警覺這種耦合,不要講任何相似但不相關的代碼合并在一起。
將變化封裝起來
在軟件領域唯一不變的就是“變化”。所以最好將你覺得將來會有改變的代碼封裝起來。這樣做的好處就是更容易測試和維護正確的被封裝的代碼。你應該先將變量聲明成 private,然后有需要的話再擴大訪問權限,如將 private 變成 protected。Java 中很多設計模式都使用了封裝,工廠設計模式就是封裝的一個例子,它封裝了對象的創建,如果要引入新的“產品”,也不必更改現有的代碼。
開放且封閉的設計理論(Open Closed Design Principle)
類、方法以及功能應該對擴展開放(新的功能),而對更改封閉。這是另一個優美的”SOLID”設計理論,這保證了有人更改已經經過測試了的代碼。如果你要加入新的功能,你必須要先測試它,這正是開放且封閉的設計理論的目標。另外,Open Closed principle 正是 SOLID 中的O的縮寫。
單一責任原理(Single Responsibility Principle (SRP))
單一責任原理是另外一條”SOLID”設計理論,代表其中的“S”。每次一個類只有一個更改的原因,或者一個類只應該完成單一的功能。如果你將多過一個功能放在一個類中,它會將兩個功能耦合在一起,如果你改變了其中的一個功能,可能會破壞另外一個功能,這樣便需要更多的測試以確保上線時不出現什么岔子。
依賴注入或反轉原理
容器會提供依賴注入,Spring 非常好的實現了依賴注入。這條原理的美妙之處在于,每個被注入的類很容易的測試和維護,因為這些對象的創建代碼都集中在容器中,有多種方法都可以進行依賴注射,譬如一些 AOP 框架如 AspectJ 使用的字節碼注入(bytecode instrumentation),以及 Spring 中使用的代理器(proxy)。來看看這個依賴注射的例子吧。這一條正是 SOLID 中的”D”。
多用組合,少用繼承
如果可能的話,多用組合,少用繼承。可能有的人會不同意,但我確實發現組合的靈活性高過繼承。組合可以在運行時通過設置某個屬性以及通過接口來組合某個類,我們可以使用多態,這樣就能隨時改變類的行為,大大提高了靈活性。Effective Java 也更傾向于使用組合。
Liskov 替代原理(Liskov Substitution Principle (LSP))
根據 Liskov 替代原理,子類必須可以替代父類,也就是使用父類的方法,也能夠沒有任何問題的和子類對象也兼容。LSP 和單一責任原則以及接口分離原則的關系緊密。如果一個類比子類的功能要多,子類不能支持父類中的某些功能的話,就違反了 LSP。為了遵循 LSP 原理,子類需要改進父類的功能,而不是減少功能。LSP 代表 SOLID 中的”L”。
接口分離理論(Interface Segregation principle (ISP))
接口分離理論強調,如果客戶端沒有使用一個接口的話,就不要實現它。當一個接口包含兩個以上的功能,如果客戶端僅僅需要其中某個功能,而不需要另外一個,那么就不要實現它。接口的設計是件非常復雜的工作,因為一旦你發布了接口之后,就再也無法保證不破壞現有實現的情況下更改接口。分離接口的另一個好處就是,因為必須要實現方法才能使用接口,所以如果僅僅只有單一的功能,那么要實現的方法也會減少。
針對接口編程,而不是針對實現編程
盡量針對接口編程,這樣如果要引入任何新的接口,也有足夠的靈活性。在變量的類型、方法的返回類型以及參量類型中使用接口類型。很多程序員都建議這么做,包括 Effective Java 和 head first design pattern 等書。
代理理論(Delegation principle)
不要所有的事情都自己做,有時候要將任務代理給相應的類去做。運用代理模式最經典的例子就是 equals ()和 hashCode ()方法。為了比較兩個對象的相等與否,我們沒有用客戶端代碼去比較,而是讓對象自己去比較。這么做的好處就是減少代碼的重復,更容易更改行為。
所有的這些面相對象理論都能幫助你寫出更靈活、高度一致且低耦合的代碼。理論是第一步,更重要的是運用這些設計理論的能力。找出違反這些設計理論的地方,但是就像這個世界上沒有什么是完美的一樣,不要嘗試著用設計模式和理論解決一切問題,因為它們往往是針對大型的企業級項目,有著更長的運行周期。換句話說小型的項目不一定值得這么做。
翻譯: ImportNew.com - 唐小娟 譯文鏈接: http://www.importnew.com/6445.html