依賴注入是一種將行為與依賴解決方案分開的技術。 用簡單的話來說,它允許開發人員定義具有特定功能的類,這些功能取決于各種協作者,而不必定義如何獲取對這些協作者的引用。 以此方式,實現了各個組件之間的解耦,并且通常引入了更簡潔的代碼。 更具體地說,一個組件僅列出必要的服務,而不是對依賴項進行硬編碼,而在運行時,一個外部獨立的組件將提供對這些服務的訪問。 我們不應忘記,依賴注入只是控制反轉的一種特殊形式,其中關注點的反轉是獲取所需依賴關系的過程。 前述技術的參考文章是Martin Fowler的 “控制容器的倒置和依賴注入模式” 。
為了注入依賴關系,已經出現了許多框架,最著名的是Spring和Guice (請參閱JavaCodeGeeks Spring相關文章)。 但是,對于小型項目使用整個框架無疑是一個過大的殺傷力。 我們的JCG合作伙伴之一, “按代碼死亡”博客的作者,撰寫了有關如何手動處理依賴項注入的小介紹。 讓我們看看他怎么說?
在另一篇文章中, “我真的需要單身人士嗎?” ,我寫了有關Singleton設計模式引入的問題的文章。 通過getInstance()方法訪問單個唯一實例時,Singleton會變相充當全局變量,并引入緊密耦合和不必要的依賴關系。 我收到了讀者的兩個直接問題:
單例應該僅與依賴注入框架一起使用嗎?
如果通過getInstance()訪問Singleton創建緊密耦合,則通過new()創建任何其他類的實例也將導致緊密耦合。 那么,如何創建一個保持松散耦合的對象?
根據我的理解,依賴注入是這兩個問題的答案。 但是,這并不要求使用框架。 依賴注入首先是一個概念,然后是一個框架。 當所討論的應用程序很小時,我們總是可以通過手動注入依賴項來滿足需求,而無需使用諸如Spring之類的框架。
在任何Java應用程序中,我們都會反復遇到兩個事件:
- 對象創建
- 對象之間的交互–業務邏輯
但是,通常我們將兩者混為一談,從而導致緊密耦合和不必要的依賴關系,這反過來又使維護以及單元測試變得痛苦。 讓我嘗試使用一個非常簡單的示例來解釋它:
class MyClass {private A a; //A is an interfaceprivate B b; //B is an interface//Object creation within constructorMyClass(A a, B b) { a = new AImpl(); //AImpl is the concrete impl of Ab = new BImpl(); //BImpl is the concrete impl of B}//Application logic lies within this methodpublic void doSomething() {//Do A specific thing//Do B specific thingC c = new CImpl(); //Object creation within the method.//Do C specific thing}
}
此類的問題是:
- 它無法將對象創建與業務邏輯分開,從而導致緊密耦合。
- 這里已經完成了“實現編程”,而不是接口。 明天,如果需要A,B或C的不同實現,則必須更改類中的代碼。
- 測試MyClass需要首先測試A,B,C。
讓我嘗試解決問題:
class MyClass {private A a;private B b;private C c;MyClass(A a, B b, C c) {//Only Assignmentthis.a = a;this.b = b;this.c = c;}//Application Logicpublic void doSomething() {//Do A specific thing//Do B specific thing//Do C specific thing}
}//The Factory
class MyFactory {public MyClass createMyClass() {return new MyClass(new AImpl(), new BImpl(), new CImpl());}
}class Main {public static void main(String args[]) {MyClass mc = new MyFactory().createMyClass();mc.doSomething();}
}
在這里已經實現了什么:
1.構造函數沒有new():
沒有在MyClass的構造函數中創建對象。 構造函數僅用于字段(A,B,C)分配。 在這里,構造函數要求依賴項作為參數,但不創建它們(這是依賴項注入的最簡單定義)。 但是,可以在構造函數內創建簡單的Collection對象(如ArrayList,HashMap或value / leaf對象,如Person / Employee)(即應用程序內的對象,這些對象又不會創建其他對象)。 構造函數不得用于任何其他操作,例如I / O,線程創建等。
根據經驗法則,任何對象都應僅保留對其直接完成工作所需的其他對象的引用(這稱為Demeter法則)。 例如,如果MyClass需要其他名為X的類,則MyClass的構造函數應直接要求X。不應要求其他工廠F可以返回X的實例。違反“ De??meter法則”將導致不必要的依賴性因此,如果您發現多個Dot(。)運算符,請當心-那里發生了非法事件。
2. Factory(MyFactory)負責對象的創建和連接:
所有新的操作員(90%-99%)應屬于工廠。 它應負責為應用程序創建整個對象圖,并應根據聲明的依賴關系關聯(連接)不同的對象(例如,MyClass需要A,B,C等)。 它不應包含任何其他內容-不應包含任何其他邏輯(沒有I / O,線程創建等)。
明天如果C開始依賴于其他稱為D的東西,則只會影響C和工廠,而不會影響整個對象圖(C必須引入重載的構造函數,并且工廠必須合并對象實例化以及與對象接線相關的更改) 。
對于大型應用程序,當然可能會有多個工廠。 在這里,經驗法則是一個工廠應該實例化具有相同壽命的所有對象。
3.對象的創建與業務邏輯是分開的:
MyClass現在是業務邏輯持有人。 它沒有任何new()。 甚至,它也不了解用于業務邏輯的具體實現(即,它了解A,但不了解AImpl,即“接口程序而不是實現程序”)。
您一定已經開始認為我是在Singleton的背景下開始討論的。 手動依賴項注入如何處理Singleton? 如何創建一個Singleton(減去緊密耦合,隱藏的依賴關系等)并在需要時訪問它? 令人驚訝的是,我們的示例中已經包含三個Singleton-AImpl,BImpl,CImpl。 如果工廠只負責創建Class的一個實例(通過僅調用new()一次),則其為Singleton。 是不是 然后,工廠可以將該依賴關系形式的唯一實例傳遞給需要它的所有其他對象。
4.那么,我們在哪里?
業務邏輯持有者MyClass的業務需要A,B和C。 它不會創建它們,而是要它們(依賴項)。 工廠(MyFactory)創建這些依賴關系并將其關聯到MyClass。 但是,誰創造了工廠? 當然是主要方法(應用程序啟動器:-)。 讓我再重復一遍這個故事:main方法首先實例化工廠,工廠反過來實例化對象圖,每個Object聲明其依賴關系,最后main方法本身設置滾動-通過調用MyClass的doSomething()啟動應用程序,即。 這些對象開始互相交談,執行日常業務。
讓我再重復一次: 創建工廠,使用工廠創建應用程序,然后啟動應用程序! 對于大規模應用程序,可以通過像Spring,Google Guice等依賴注入框架來實現相同的目的。當然,它們還將帶來許多其他好處。 但是,對于中小型應用程序,可以手動制作依賴項注入,從而使應用程序松散耦合,更易于維護,并且當然可以進行單元測試。
- 使用Spring AspectJ和Maven進行面向方面的編程
- JBoss 4.2.x Spring 3 JPA Hibernate教程
- GWT Spring和Hibernate進入數據網格世界
- 建立自己的GWT Spring Maven原型
- GWT 2 Spring 3 JPA 2 Hibernate 3.5教程– Eclipse和Maven 2展示
- 使用Spring使用Java發送電子郵件– GMail SMTP服務器示例
翻譯自: https://www.javacodegeeks.com/2010/12/dependency-injection-manual-way.html