Java程式設計師應該知道的10個物件導向理論

importnew發表於2013-10-27

  物件導向理論是物件導向程式設計的核心,但是我發現大部分Java程式設計師熱衷於像單例模式、裝飾者模式或觀察者模式這樣的設計模式,而並沒有十分注意學習物件導向的分析和設計。學習面向程式設計的基礎(如抽象,封裝,多型,繼承等)是非常重要的,而運用它們來設計乾淨的模組也同樣重要。我也認識很多不同等級的程式設計師,他們沒有聽過這些物件導向理論,或者不知道某個設計理論有什麼好處,或者如何在編碼中使用這些設計理論。

  我們起碼要設計出高度一致而且鬆散耦合的程式碼。Apache和Sun的原始碼就是學習Java物件導向理論的非常好的例子。JDK遵循了一些設計模式,譬如在BorderFactory中使用工廠模式,Runtime類中使用單例模式,java.io中的許多類中使用裝飾者模式。如果你真的對Java程式設計感興趣,請先閱讀Joshua Bloch的Effective Java,正是他參與編寫了Java API。另外兩本我喜歡的關於設計模式的書還有,Kathy Sierra等編寫的的Head First Design PatternHead 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 Javahead first design pattern等書。

  代理理論(Delegation principle)

  不要所有的事情都自己做,有時候要將任務代理給相應的類去做。運用代理模式最經典的例子就是equals()和hashCode()方法。為了比較兩個物件的相等與否,我們沒有用客戶端程式碼去比較,而是讓物件自己去比較。這麼做的好處就是減少程式碼的重複,更容易更改行為。

  所有的這些面相物件理論都能幫助你寫出更靈活、高度一致且低耦合的程式碼。理論是第一步,更重要的是運用這些設計理論的能力。找出違反這些設計理論的地方,但是就像這個世界上沒有什麼是完美的一樣,不要嘗試著用設計模式和理論解決一切問題,因為它們往往是針對大型的企業級專案,有著更長的執行週期。換句話說小型的專案不一定值得這麼做。

  本文由 ImportNew - 唐小娟 翻譯自 Javarevisited

相關文章