国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
Transparent Dependency Injection For Rich Domain Model 2

在上一章 Dependency Injection For Rich Domain Model 中, 我們給出了一種通過顯式調(diào)用"injector.inject(domain_obj)"的方法來解決對這些域?qū)ο蟮淖⑸涞姆椒?。這個方法基本上屏蔽了依賴注射的復雜性,也避免了對aop或者容器的依賴,保證了單體測試的方便。

然而,程序員的美德是懶惰的。被迫調(diào)用一些inject()函數(shù)還是讓人不是太爽??吹絘op的那種完全不需要關(guān)心依賴的簡單,我們能不能做點什么呢?

完全透明的注射而不用aop,可能嗎?

答案是肯定的。

我們的理想是,讓DAO對象在返回BankAccount的時候就自動把依賴設(shè)置好??墒?,我們前面也分析了,DAO層的代碼是不可能也不應該知道業(yè)務(wù)層的那些依賴的。讓BankAccountDaoImpl非要知道SmtpService也顯得很滑稽。看來似乎除了aop一家,別無分店了。

山重水盡疑無路,柳暗花明又一村。我們還是在重重困難中看到了一線光明。proxy,對,我們不用full-blown的aop,但是我們可以用OO的經(jīng)典模式:proxy來把BankAccountDaoImpl封裝成一個知道這些依賴的對象。如此:

class BankAccountService{private final BankAccountDao dao;BankAccount getAccountById(String id){return dao.getById(id);}public BankAccountService(BankAccountDao dao){this.dao = dao;}...}

我們可以假設(shè)這個Dao沒有返回半成品,而是一個完全有效的完整的BankAccount。

同時,我們不希望改動BankAccountDaoImpl類,它仍然保持它對業(yè)務(wù)層的一無所知。只不過,在組裝BankAccontService的時候,我們做點手腳:

new BankAccountService(new DaoProxy(new BankAccountDaoImpl(), new SmtpService()));

通過把BankAccountDaoImpl傳遞給一個proxy,我們可以得到一個滿足我們需要的BankAccountDao對象。

這個proxy怎么寫呢?一個naive的實現(xiàn)如下:

class BankAccountDaoProxy implements BankAccountDao{private final SmtpService smtp;private final BankAccountDao dao;public BankAccount getById(String id){BankAccount acc = dao.getById(id);acc.setSmtpService(smtp);return acc;}...}

不過,這個解決方案雖然簡單,卻比較笨拙:

  1. 我們需要手工注射所有的依賴。調(diào)用這些setSmtpService(), setWebService()等等等等setter。
  2. 我們需要給每個BankAccount類型的返回值注射依賴。很累人。

對于第一點,我們還可以用 Dependency Injection For Rich Domain Model 中提到的Injector接口來抽象它。對于第二點,可以考慮使用java的動態(tài)代理來實現(xiàn)。最終,我們希望容器在注射BankAccountDao給BankAccountService的時候能夠注射這個代理。這樣,所有的依賴仍然被容器管理。在程序代碼中,我們得到了使用aop同樣的好處,但是卻沒有引入對aop的依賴。

Yan對充血domain object的依賴注射的完整解決方案

InjectorHelper

類對這個問題提供了完整的解決方案。使用這個類,我們可以把組裝代碼變成這樣:

void registerBankAccountService(Container yan){Binder injection = new Binder(){public Creator bind(Object obj){return Components.value(obj).bean(new String[]{"smtpService"});}};Component dao_impl = Components.ctor(BankAccountDaoImpl.class);InjectorHelper helper = new InjectorHelper();Component dao = helper.getProxyComponentReturningInjected(BankAccountDao.class, dao_impl, BankAccount.class, injection);yan.registerComponent("bankaccount_service",Components.ctor(BankAccountService.class).withArgument(0, dao);}
  • 對域?qū)ο蟮淖⑸淙匀挥靡粋€Binder對象表示。
  • InjectorHelper.getProxyComponentReturningInjected(...) 負責把dao_impl這個生成BankAccountDaoImpl對象的組件轉(zhuǎn)換為一個生成我們需要的proxy的組件。
  • getProxyComponentReturningInjected()的第一個參數(shù)是目標接口。這個proxy必須實現(xiàn)這個BankAccountDao接口。
  • 第二個參數(shù)是一個生成那個被代理對象的組件。
  • 第三個參數(shù)是需要注射依賴的返回值類型。我們只對BankAccount類型的對象注射依賴。
  • 第四個參數(shù)是注射的具體邏輯。

如此,通過容器的支持,我們可以完美地給充血對象注射依賴了。

給若干種類型的返回值注射依賴

假設(shè),我們的BankAccountImpl還可能返回Bank這個也需要注射依賴的充血對象,怎么辦?其實很簡單,我們只要再多調(diào)用一次getProxyComponentReturningProxy()函數(shù)就可以了。如下:

void registerBankAccountService(Container yan){Binder bankaccount_injection = ...;Binder bank_injection = ...;Component dao_impl = Components.ctor(BankAccountDaoImpl.class);InjectorHelper helper = new InjectorHelper();Component dao = helper.getProxyComponentReturningInjected(BankAccountDao.class, dao_impl, BankAccount.class, bankaccount_injection);dao = helper.getProxyComponentReturningInjected(BankAccountDao.class, dao, Bank.class, bank_injection);yan.registerComponent("bankaccount_service",Components.ctor(BankAccountService.class).withArgument(0, dao);}

這里,我們對一個dao組件包裝了兩層代理,頭一層代理負責對BankAccount類型的返回值進行注射。第二個代理負責對Bank類型的返回值進行注射。
如此,兩種injection邏輯就都可以被綁在組件上了。

程序中直接創(chuàng)建的域?qū)ο笤趺崔k?

上面的方法封裝了dao,保證dao返回的都是依賴注射已經(jīng)完成的可用對象。那么如果我這么做怎么辦?

class BankAccountUser{void f(){BankAccount account = new BankAccount();account.sendMail(...);}}

這個代碼仍然不能工作因為sendMail所依賴的smtp service沒有被設(shè)置。

對這種問題,我們建議采用下面這種方法:
不直接調(diào)用構(gòu)造函數(shù),而是定義一個BankAccountFactory的接口。采用上面同樣的方法,容器可以注射一個能夠處理依賴的BankAccountFactory實現(xiàn)。比如:

public class BankAccountUser{public BankAccountUser(BankAccountFactory factory){...}private final BankAccountFactory factory;void f(){BankAccount account = factory.newBankAccount();account.sendMail(...);}}
void registerBankAccountUser(Container yan){Component ctor = Components.ctor(BankAccount.class);Component factory = ctor.bean(new String[]{"smtpService"}).factory(BankAccountFactory.class);Component user = Components.ctor(BankAccountUser.class).withArgument(0, factory);yan.registerComponent("bankaccountuser", user);}
  • xxx.factory(BankAccountFactory.class) 創(chuàng)建一個組件,這個組件在被實例化的時候,會返回一個BankAccountFactory類型的對象。這個對象會采用 xxx 所定義的邏輯來生成對象。

結(jié)論

本文中,我們闡述了Martine Fowler倡導的rich domain object模型。提出了在這個模型中的依賴注入的尷尬困境。
我們比較了現(xiàn)在一些流行的方法(使用aop攔截)。

最后,我們給出了一個作用類似于aop的攔截,但是本身不依賴aop而僅僅用純粹的ioc依賴注射的方法。
在這種方法中,domain object的使用者可以假設(shè)dao返回的是一個完全可用的rich domain object,所有的依賴問題都被轉(zhuǎn)移到容器中管理。

不同于采用aop的方法,整個解決方案是完全的dependency injection,沒有service locator。單元測試能力也沒有受到影響。

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
spring面試題
Java工廠模式、Ioc和AOP 框架設(shè)計
PostSharp Blog | Aspect
Terasoluna學習手記之配置文件applicationContext.xml
使用 Hibernate 和 Spring AOP 構(gòu)建泛型類型安全的 DAO
Java下的框架編程(反射,泛型,元數(shù)據(jù),CGLib,代碼動態(tài)生成,AOP,動態(tài)語言嵌入)
更多類似文章 >>
生活服務(wù)
分享 收藏 導長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服