周洪斌
?。ㄉ持蘼殬I(yè)工學(xué)院,,江蘇 張家港 215600)
摘要:IoC是一種優(yōu)秀的組件解耦模式,而依賴注入是IoC最流行的實現(xiàn)方式,。探討了依賴注入的三種不同的實現(xiàn)方式:構(gòu)造器注入,、屬性注入以及接口注入,并介紹了IoC容器Unity的基本使用方法,。
關(guān)鍵詞:依賴倒置原則,;控制反轉(zhuǎn);依賴注入,;Unity
0引言
2015年江蘇省高校大學(xué)生創(chuàng)新創(chuàng)業(yè)訓(xùn)練計劃立項項目(201511288009Y)在使用簡單三層架構(gòu)開發(fā)數(shù)據(jù)庫應(yīng)用程序時,,一般都是在業(yè)務(wù)邏輯層直接創(chuàng)建數(shù)據(jù)訪問層相應(yīng)的對象,如:
public class ProductBLL
{
SqlServerDAL dal = new SqlServerDAL();
public int Add(ProductModel model)
{
return dal.Add(model);
}
}
這種方式下由調(diào)用者ProductBLL主動創(chuàng)建被依賴對象SqlServerDAL,,然后調(diào)用被依賴對象的方法,,導(dǎo)致調(diào)用者與被依賴對象實現(xiàn)類的硬編碼耦合,不利于項目的維護與升級,。上述緊耦合的業(yè)務(wù)邏輯層與數(shù)據(jù)訪問層的關(guān)系如圖1所示,。
如果用戶需要將數(shù)據(jù)庫換成Access或者MySQL,需要修改ProductBLL類內(nèi)部的代碼,,違反了開放封閉原則,。開放封閉原則要求“軟件實體(類、模塊,、函數(shù)等)對擴展是開放的,,對修改是封閉的”。依賴倒置原則(Dependency Inversion Principle,,DIP)要求“高層模塊不應(yīng)該依賴于低層模塊,,兩者應(yīng)該依賴于抽象”[1]。因此,,業(yè)務(wù)邏輯層的對象不應(yīng)該直接依賴于數(shù)據(jù)訪問層的具體實現(xiàn)對象,,而應(yīng)該通過數(shù)據(jù)訪問層的抽象接口進行訪問,如圖2所示,。通過引入抽象,,對于高層模塊而言,低層模塊的實現(xiàn)是可替換的。這實際上也是“開放封閉原則”的體現(xiàn),。
1控制反轉(zhuǎn)
DIP作為一種軟件設(shè)計原則,,指明了兩個模塊之間應(yīng)該如何依賴。而控制反轉(zhuǎn)(Inversion of Control,,IoC)則是一種具體的軟件設(shè)計模式,明確了如何解除相互依賴的模塊之間的耦合,。IoC是指應(yīng)用本身不負責(zé)依賴對象的創(chuàng)建和維護,,而交給一個外部容器來完成。這樣就將控制權(quán)由應(yīng)用轉(zhuǎn)移到了外部,,實現(xiàn)了控制權(quán)的反轉(zhuǎn)[2],。IoC的作用在于降低組件之間的耦合度,減少組件之間的依賴關(guān)系,,提高程序的靈活性和可維護性,。
依賴注入(Dependency Injection,DI)是IoC模式最流行的實現(xiàn)方式,,即由外部容器在運行時動態(tài)地將依賴的對象注入到組件中,。通過依賴注入,業(yè)務(wù)邏輯層將不再需要直接創(chuàng)建數(shù)據(jù)訪問層的對象,,從而降低了兩者之間的耦合度,。
2依賴注入
依賴注入提供一種機制,將需要依賴(低層模塊)對象的引用傳遞給被依賴(高層模塊)對象,。具體的依賴注入可以分為三種形式,,即構(gòu)造器注入、屬性注入以及接口注入[3],。
2.1構(gòu)造器注入
構(gòu)造器注入,,即通過構(gòu)造方法傳遞依賴。根據(jù)依賴倒置原則,,高層模塊不應(yīng)該依賴于低層模塊,,兩者應(yīng)該依賴于抽象。因此構(gòu)造方法的參數(shù)應(yīng)該是一個抽象類型,。
首先,,需要定義一個接口IDataAccess,并在IDataAccess接口中聲明一個Add方法,,代碼如下:
public interface IDataAccess
{
int Add(ProductModel model);
}
然后,,在SqlServerDAL類中,實現(xiàn)IDataAccess接口,,代碼如下:
public class SqlServerDAL:IDataAccess
{
public int Add(ProductModel model)
{
//省略具體數(shù)據(jù)庫操作代碼
}
}
接下來,,修改ProductBLL類的代碼,代碼如下:
public class ProductBLL
{
private IDataAccess dal;
//構(gòu)造器注入
public ProductBLL(IDataAccess dal)
{
this.dal=dal;//傳遞依賴
}
public int Add(ProductModel model)
{
return dal.Add(model);
}
}
在這里,將依賴對象SqlServerDAL對象的創(chuàng)建和綁定轉(zhuǎn)移到ProductBLL類的外部來實現(xiàn),,這樣就解除了兩者之間的緊耦合關(guān)系,。這時,如果要將數(shù)據(jù)庫換成Access數(shù)據(jù)庫時,,只需定義一個AccessDAL類,,實現(xiàn)IDataAccess接口,然后在外部重新綁定依賴,,不需要修改ProductBLL類內(nèi)部代碼即可實現(xiàn)對Access數(shù)據(jù)庫的操作,。
2.2屬性注入
屬性注入,即通過屬性來傳遞依賴,。因此,,首先需要在依賴類ProductBLL中定義一個屬性,代碼如下:
public class ProductBLL
{
private IDataAccess dal;
//屬性,,接受依賴
public IDataAccess Dal
{
set { dal = value; }
get { return dal; }
}
public int Add(ProductModel model)
{
return dal.Add(model);
}
}
然后在外部通過給Dal屬性賦值,,從而傳遞依賴。
2.3接口注入
接口注入需要先定義一個接口,,包含一個設(shè)置依賴的方法,。然后由依賴類繼承并實現(xiàn)這個接口。
首先定義一個接口,,代碼如下:
public interface IDependent
{
void SetDependence(IDataAccess dal);//設(shè)置依賴項
}
依賴類實現(xiàn)這個接口,,代碼如下:
public class ProductBLL:IDependent
{
private IDataAccess dal;
//實現(xiàn)接口
public void SetDependence(IDataAccess dal)
{
this.dal = dal;
}
public int Add(ProductModel model)
{
return dal.Add(model);
}
}
外部則通過SetDependence方法傳遞依賴。相比構(gòu)造器注入和屬性注入,,接口注入顯得有些復(fù)雜,,使用也不常見。
3IoC容器
3.1IoC容器概述
一般在小型項目中可以手動創(chuàng)建依賴對象,,并將引用傳遞給被依賴模塊,。如:
IDataAccess dal=new SqlServerDAL();//在外部創(chuàng)建依賴對象
ProductBLL bll=new ProductBLL(dal);//通過構(gòu)造器注入依賴
對于大型項目來說,相互依賴的組件比較多,,如果還用手動的方式來創(chuàng)建和注入依賴,,效率較低。正因如此,,IoC容器誕生了,。IoC容器實際上是一個依賴注入框架,它包含以下幾個功能:
?。?)動態(tài)創(chuàng)建,、注入依賴對象;
?。?)管理對象生命周期,;
?。?)映射依賴關(guān)系。
Spring是Java平臺廣泛使用的IoC容器[4],,.NET平臺常用的IoC容器包括Unity,、Autofac、Spring.NET和Ninject等,。Unity是微軟公司推出的一款輕量的,、可擴展的依賴注入容器,該項目在Codeplex上的地址為http://unity.codeplex.com,,可以下載相應(yīng)的安裝包和開發(fā)文檔[5],。
3.2Unity應(yīng)用
Unity在實際項目中的使用方法如下[6]:
(1)添加對Microsoft.Practices.Unity.dll,、Microsoft.Practices.Unity.Configuration.dll以及Microsoft.Practices.Unity.RegistrationByConvention.dll的引用。
?。?)在項目配置文件的<configSections>節(jié)點下注冊名為unity的section,,并在<configuration>節(jié)點下添加unity配置信息。配置文件樣例如下:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/>
</configSections>
<unity>
<container name="MyContainer">
<!--映射關(guān)系-->
<register type="UnityDemo.IDataAccess,UnityDemo"mapTo="UnityDemo.SqlServerDAL,UnityDemo"></register>
</container>
</unity>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
</startup>
</configuration>
?。?)在代碼中讀取配置信息,,并將配置載入到UnityContainer中。
//創(chuàng)建容器
IUnityContainer container = new UnityContainer();
//載入配置信息
container.LoadConfiguration("MyContainer");
//獲取指定名稱的配置節(jié)
UnityConfigurationSection section
= (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
//獲取特定配置節(jié)下已命名的配置節(jié)<container name='MyContainer'>下的配置信息
section.Configure(container, "MyContainer");
//創(chuàng)建實現(xiàn)了IDataAccess接口的對象
IDataAccess dal = container.Resolve<IDataAccess>();
4結(jié)論
IoC能有效降低組件之間的耦合度,,提高程序的靈活性和可擴展性,。本文圍繞如何實現(xiàn)業(yè)務(wù)邏輯層與數(shù)據(jù)訪問層之間的松散耦合,介紹了構(gòu)造器注入,、屬性注入以及接口注入三種不同的依賴注入方式,,并介紹了NET平臺下常用IoC容器Unity的使用,展示了IoC在軟件開發(fā)領(lǐng)域的實際應(yīng)用,。
參考文獻
?。?] 張逸.軟件設(shè)計精要與模式(第2版)[M].北京:電子工業(yè)出版社,2010.
[2] 王程,周安琳.基于Autofac對乳制品安全風(fēng)險預(yù)警系統(tǒng)的擴展設(shè)計[J].河北省科學(xué)院學(xué)報,2013,30(1):14.
?。?] 張浩.利用反向控制原則和依賴注入的可復(fù)用框架設(shè)計解耦方法[J].計算機應(yīng)用,2010(12):227229.
?。?] 周嵐.基于Spring框架的IoC模式的設(shè)計和實現(xiàn)[J].合肥學(xué)院學(xué)報(自然科學(xué)版),2011,21(1):4953.
[5] 李鳳桐.微軟企業(yè)庫組件Unity使用淺析[J].電腦編程技巧與維護,2015(6):1314.
?。?] 蔣金楠.ASP.NET MVC4框架揭秘[M].北京:電子工業(yè)出版社,2013.