[TOC=1,2]
面向對象理論是面向對象編程的核心,但是我發現大部分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()方法。為了比較兩個對象的相等與否,我們沒有用客戶端代碼去比較,而是讓對象自己去比較。這么做的好處就是減少代碼的重復,更容易更改行為。
所有的這些面相對象理論都能幫助你寫出更靈活、高度一致且低耦合的代碼。理論是第一步,更重要的是運用這些設計理論的能力。找出違反這些設計理論的地方,但是就像這個世界上沒有什么是完美的一樣,不要嘗試著用設計模式和理論解決一切問題,因為它們往往是針對大型的企業級項目,有著更長的運行周期。換句話說小型的項目不一定值得這么做。
原文鏈接: Javarevisited 翻譯: ImportNew.com - 唐小娟
譯文鏈接: http://www.importnew.com/6445.html
- JVM
- 深入理解Java內存模型
- 深入理解Java內存模型(一)——基礎
- 深入理解Java內存模型(二)——重排序
- 深入理解Java內存模型(三)——順序一致性
- 深入理解Java內存模型(四)——volatile
- 深入理解Java內存模型(五)——鎖
- 深入理解Java內存模型(六)——final
- 深入理解Java內存模型(七)——總結
- Java內存模型
- Java內存模型2
- 堆內內存還是堆外內存?
- JVM內存配置詳解
- Java內存分配全面淺析
- 深入Java核心 Java內存分配原理精講
- jvm常量池
- JVM調優總結
- JVM調優總結(一)-- 一些概念
- JVM調優總結(二)-一些概念
- VM調優總結(三)-基本垃圾回收算法
- JVM調優總結(四)-垃圾回收面臨的問題
- JVM調優總結(五)-分代垃圾回收詳述1
- JVM調優總結(六)-分代垃圾回收詳述2
- JVM調優總結(七)-典型配置舉例1
- JVM調優總結(八)-典型配置舉例2
- JVM調優總結(九)-新一代的垃圾回收算法
- JVM調優總結(十)-調優方法
- 基礎
- Java 征途:行者的地圖
- Java程序員應該知道的10個面向對象理論
- Java泛型總結
- 序列化與反序列化
- 通過反編譯深入理解Java String及intern
- android 加固防止反編譯-重新打包
- volatile
- 正確使用 Volatile 變量
- 異常
- 深入理解java異常處理機制
- Java異常處理的10個最佳實踐
- Java異常處理手冊和最佳實踐
- Java提高篇——對象克隆(復制)
- Java中如何克隆集合——ArrayList和HashSet深拷貝
- Java中hashCode的作用
- Java提高篇之hashCode
- 常見正則表達式
- 類
- 理解java類加載器以及ClassLoader類
- 深入探討 Java 類加載器
- 類加載器的工作原理
- java反射
- 集合
- HashMap的工作原理
- ConcurrentHashMap之實現細節
- java.util.concurrent 之ConcurrentHashMap 源碼分析
- HashMap的實現原理和底層數據結構
- 線程
- 關于Java并發編程的總結和思考
- 40個Java多線程問題總結
- Java中的多線程你只要看這一篇就夠了
- Java多線程干貨系列(1):Java多線程基礎
- Java非阻塞算法簡介
- Java并發的四種風味:Thread、Executor、ForkJoin和Actor
- Java中不同的并發實現的性能比較
- JAVA CAS原理深度分析
- 多個線程之間共享數據的方式
- Java并發編程
- Java并發編程(1):可重入內置鎖
- Java并發編程(2):線程中斷(含代碼)
- Java并發編程(3):線程掛起、恢復與終止的正確方法(含代碼)
- Java并發編程(4):守護線程與線程阻塞的四種情況
- Java并發編程(5):volatile變量修飾符—意料之外的問題(含代碼)
- Java并發編程(6):Runnable和Thread實現多線程的區別(含代碼)
- Java并發編程(7):使用synchronized獲取互斥鎖的幾點說明
- Java并發編程(8):多線程環境中安全使用集合API(含代碼)
- Java并發編程(9):死鎖(含代碼)
- Java并發編程(10):使用wait/notify/notifyAll實現線程間通信的幾點重要說明
- java并發編程-II
- Java多線程基礎:進程和線程之由來
- Java并發編程:如何創建線程?
- Java并發編程:Thread類的使用
- Java并發編程:synchronized
- Java并發編程:Lock
- Java并發編程:volatile關鍵字解析
- Java并發編程:深入剖析ThreadLocal
- Java并發編程:CountDownLatch、CyclicBarrier和Semaphore
- Java并發編程:線程間協作的兩種方式:wait、notify、notifyAll和Condition
- Synchronized與Lock
- JVM底層又是如何實現synchronized的
- Java synchronized詳解
- synchronized 與 Lock 的那點事
- 深入研究 Java Synchronize 和 Lock 的區別與用法
- JAVA編程中的鎖機制詳解
- Java中的鎖
- TreadLocal
- 深入JDK源碼之ThreadLocal類
- 聊一聊ThreadLocal
- ThreadLocal
- ThreadLocal的內存泄露
- 多線程設計模式
- Java多線程編程中Future模式的詳解
- 原子操作(CAS)
- [譯]Java中Wait、Sleep和Yield方法的區別
- 線程池
- 如何合理地估算線程池大小?
- JAVA線程池中隊列與池大小的關系
- Java四種線程池的使用
- 深入理解Java之線程池
- java并發編程III
- Java 8并發工具包漫游指南
- 聊聊并發
- 聊聊并發(一)——深入分析Volatile的實現原理
- 聊聊并發(二)——Java SE1.6中的Synchronized
- 文件
- 網絡
- index
- 內存文章索引
- 基礎文章索引
- 線程文章索引
- 網絡文章索引
- IOC
- 設計模式文章索引
- 面試
- Java常量池詳解之一道比較蛋疼的面試題
- 近5年133個Java面試問題列表
- Java工程師成神之路
- Java字符串問題Top10
- 設計模式
- Java:單例模式的七種寫法
- Java 利用枚舉實現單例模式
- 常用jar
- HttpClient和HtmlUnit的比較總結
- IO
- NIO
- NIO入門
- 注解
- Java Annotation認知(包括框架圖、詳細介紹、示例說明)