欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
Dependency Injection For Rich Domain Model 1

本文中,我們將簡(jiǎn)要介紹一下在應用Martin Fowler所推薦的rich domain model模型中遇到的依賴(lài)注射的問(wèn)題。然后在本文后半部分我們給出一個(gè)相對比較簡(jiǎn)單的利用Yan容器來(lái)管理這些域對象的依賴(lài)的方法。這個(gè)方法不要求程序對容器有任何直接或者間接的依賴(lài),如果愿意,我們完全可以用手工注射作為一個(gè)實(shí)現策略。(當然,它要求容器有足夠的靈活性來(lái)處理這種依賴(lài)管理。)

然后,在下一章Transparent Dependency Injection for Rich Domain Model中,我們介紹Yan提供的一種結合動(dòng)態(tài)代理的更加方便的解決方案。

hyperaemia domain model

在討論domain model的時(shí)候,我驚訝地發(fā)現,一些同志在應用馬丁同學(xué)的充血模型(hyperaemia)的時(shí)候,為如何給這些從hibernate創(chuàng )建而來(lái)的domain對象怎么注射依賴(lài)而煩惱.

hibernate或者Dao,不可能知道你的充血對象都需要什么外部的依賴(lài)。對hibernate來(lái)說(shuō),不管你對象是否充血,它都是當作一個(gè)簡(jiǎn)單的結構來(lái)往里填入數據成員。這其實(shí)很尷尬,尤其是對Dao,它將返回一個(gè)半成品對象,這個(gè)對象只有一些數據成員被設置,而其它的對這個(gè)對象的功能至關(guān)重要的依賴(lài)卻還沒(méi)有被建立。這是什么樣的一個(gè)Dao阿。返回一個(gè) "小心!它看起來(lái)是BankAccount,但是千萬(wàn)別當作BankAccount用呢先,你得先設置各種依賴(lài)關(guān)系。" 。

我發(fā)現我怎么就無(wú)論如何喜歡不起來(lái)這種充血模型呢?一個(gè)好的設計,應該盡量用靜態(tài)類(lèi)型來(lái)表示設計意圖。盡量讓符合類(lèi)型要求的操作合法化,而不符合類(lèi)型要求的操作非法。在這個(gè)充血模型里面,事情卻不是這么簡(jiǎn)單。從Dao返回出來(lái)的BankAccount不是真正的BankAccount.

更優(yōu)雅的設計,在我看來(lái),應該是Dao只返回純數據的結構,比如BankAccountData,這個(gè)對象里除了getter/setter就沒(méi)有業(yè)務(wù)邏輯。然后在service層面把BankAccountData轉換為BankAccount。這樣,就不存在一個(gè)半成品的狀態(tài),不存在假象。類(lèi)型告訴我們什么可用,什么就必然可用。

當然,這也許比較麻煩,畢竟多了一個(gè)轉換的步驟,多了BankAccountData這個(gè)類(lèi)型。

AOP?

好了,不唧唧歪歪了。讓我們看看同學(xué)們頭疼的注射依賴(lài)問(wèn)題。

目前,包括xiecc同學(xué)在內的許多朋友都不約而同地選擇用aop來(lái)完成這個(gè)依賴(lài)注射,我們不用這種手工注射:

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

而是:

class BankAccountService{private final SmtpService smtp;private final BankAccountDao dao;BankAccount getBankAccountById(String id){BankAccount acc = dao.getById(id);//acc.setSmtpService(smtp);    return acc;}}

簡(jiǎn)單地把acc.setSmtpService給注釋掉。這段代碼雖然簡(jiǎn)短,看起來(lái)很費解,因為明明smtpService沒(méi)有被設置,這個(gè)BankAccount仍然還是個(gè)半成品嘛。

然后,弄一個(gè)aspect,讓它偷偷把smtpService注射給BankAccount。

什么?aspect怎么知道smtpService?當然是service locator了。通過(guò)主動(dòng)在容器里查詢(xún),找到smtpService不就好了?

我來(lái)給這個(gè)方法挑挑毛?。?/p>

  1. 上面說(shuō)過(guò)了。代碼不容易理解。明明setSmtpService沒(méi)有被調用,不知道有個(gè)aop會(huì )在預定地點(diǎn)冒出來(lái)得人抓破頭皮也看不懂這程序怎么工作的。
  2. 不容易u(yù)nit test。這個(gè)代碼能夠工作,完全依賴(lài)于aop的存在。即使在單體測試,aop,以及容器也必須包含在內。
  3. aspect的代碼內部仍然是service locator,而不能dependency injection。而service locator的缺點(diǎn)就跟jndi一樣的。
  4. aop呀?aop一般不是為了所謂cross-cut concern設計的嗎?我們看看這里的setSmtpService是cross-cut concern嗎?它不明顯是整個(gè)邏輯的不可分割的一部分嗎?這不是橫切,而是亂攪和。
  5. aop。相當重量級的東西呀。就為了這么個(gè)dependency injection就引入這么大代價(jià)?

回歸ioc。

那么,我們推薦什么樣的方法呢?

  • 首先,這個(gè)方法要足夠簡(jiǎn)單。不引入額外的復雜性。
  • 其次,它應該對單體測試友好。
  • 最后,代碼應該更易懂。

怎么辦?還是ioc。任何時(shí)候,ioc都是我們堅持的原則。

仔細分析需求,我們這里不是要尋找容器,也不是要個(gè)aop,真正最根本的需要是“依賴(lài)注射”。
根據我們面向接口編程的原則,任何時(shí)候,如果需要某個(gè)外界提供的功能,用接口把它描述出來(lái),然后讓外界注射進(jìn)來(lái)。當然,我們這里需要從外界注射的是一個(gè)“依賴(lài)注射邏輯”。有點(diǎn)繞是么?呵呵,看看代碼把:

public interface Injector{void inject(Object obj);}class BankAccountService{private final Injector injector;private final BankAccountDao dao;BankAccountService(Injector injector, BankAccountDao dao){this.injector = injector;this.dao = dao;}BankAccount findAccountById(String id){BankAccount acc = dao.getById(id);injector.inject(acc);return acc;}}

好了,domain object和service的設計到此為止。剩下的就是衣來(lái)伸手,飯來(lái)張口,等著(zhù)外面給我注射這個(gè)我自家用的注射器了。

這個(gè)代碼完全是單體測試友好的。因為我甚至可以簡(jiǎn)單地用手工注射來(lái)實(shí)現Injector。比如:

Injector manual_injector = new Injector(){public Object inject(Object obj){BankAccount acc = (BankAccount)obj;acc.setSmtpService(new SmtpService());}};

閱讀起來(lái),這個(gè)代碼也是自我解釋的。injector.inject(acc)負責注射依賴(lài),于是然后BankAccount就是一個(gè)完整的rich domain object了。邏輯清晰直白。

它也不依賴(lài)容器,aop等任何不該依賴(lài)的東西,就是一個(gè)傳統的嚴謹的ioc設計。

從容器注射

下面探討怎么從Yan

的容器給這個(gè)Service注射Injector。

首先,因為這些注射都是基于某個(gè)不是容器創(chuàng )建的對象進(jìn)行的,我們用Binder

接口來(lái)描述這些注射邏輯。在這個(gè)例子中,我們只關(guān)心smtpService這個(gè)property:

Binder injection = new Binder(){public Creator bind(Object obj){return Components.value(obj).bean(new String[]{"smtpService"});}};

這個(gè)bind()函數返回的Component對象就負責對這個(gè)參數??obj??的smtpService進(jìn)行注射。

接下來(lái),需要把這個(gè)Binder對象轉換成一個(gè)生成Injector實(shí)例的Component,InjectorHelper

這個(gè)幫助類(lèi)可以被用來(lái)進(jìn)行這個(gè)轉換:

void registerBankAccountService(Container yan){Component some_dao_component = ...;Binder injection = ...;InjectorHelper helper = new InjectorHelper();Component injector = helper.getInjectorComponent(Injector.class, injection);yan.registerComponent("bankaccount_service",Components.ctor(BankAccountService.class).withArgument(0, some_dao_component).withArgument(1, injector);}
  • new InjectorHelper() 創(chuàng )建一個(gè)InjectorHelper對象。
  • helper.getInjectorComponent(Injector.class, injection) 把這個(gè)Binder對象轉換為一個(gè)可以創(chuàng )建Injector接口實(shí)例的Component。
  • 最后, 這個(gè) injector 組件被制定作為BankAccountService這個(gè)組件的第二個(gè)參數. 這樣,這個(gè)把注射器注射給Service的任務(wù)就算完成了。
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
簡(jiǎn)化Spring(2)--Model層
spring框架學(xué)習(一)
spring面試題
Promise的前世今生和妙用技巧
MyBatis-plus配置自定義SQL(執行用戶(hù)傳入SQL)
關(guān)于 Angular 的 hierarchical injector
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久