控制反轉,即IOC(Inversion of Control),也叫反轉模式,也稱依賴注入DI(Dependency Injection)模式,關於此概念的解釋我在此文不做過講說明。
對於設計模式類的東西,我也沒有認真系統的去研究過那X類N種設計模式,無論何種設計模式,都用於解決一個問題,那就是解決對象之間的耦合關系,即解耦。
AgileEAS.NET在最初版本最不包含IOC容器,更多應用抽象工廠之類的設計模式,在這AgileEAS.NET大概第二個版本,加入了一個輕量級(微量級)的IOC容器,也許實現的並不優雅,在多年的應用中慢慢完善。
以下我列舉一個 AgileEAS.NET平台IOC容器的一個應用場景,在某個產品開發中,有的產品使用ORACLE數據庫、有的客戶使用SQLServer數據庫,這就要求我們必須做到產品同時支持兩種數據庫,我們在開發中對數據DAL采用其他接口驅動的設計,即定義三個項目:DAL接口、DAL的SQLServer 實現、DAL的ORACLE實現,假定三個項目名稱為Exam.DAL.Interface、Exam.DAL.SQLServer、 Exam.DAL.Oracle;我們在Exam.DAL.Interface中定義N個業務對象接口和一個管理這些業務對象接口的 IDALManager接口:
public interface IDALManager
{
IIteminfo CreateIteminfo();
IIteminfoList CreateIteminfoList();
IProduct CreateProduct();
IProductList CreateProductList();
}
我們在Exam.DAL.SQLServer、Exam.DAL.Oracle中分別實現業務接口和IDALManager接口:
public class DALManager : IDALManager
{
public IIteminfo CreateIteminfo()
{
return new Iteminfo();
}
public IIteminfoList CreateIteminfoList()
{
return new IteminfoList();
}
public IProduct CreateProduct()
{
return new Product();
}
public IProductList CreateProductList()
{
return new ProductList();
}
}
我們力爭在設計中使用接口驅動並且使用具體被調用者在運行期確認,當然在這樣的應用場景中除了IOC容器之外可以用其他模式進行實現,我在此不做說明。
我們在Exam.DAL.Interface增加一個公共類DALHelper並做如下定義:
public class DALHelper
{
public DALHelper()
{
}
public static IDALManager DALManager
{
get
{
return ContextHelper.GetContext().Container.GetComponentInstance("EAS.Exam.DAL") as IDALManager;
}
}
}
修改系統配件文件中的IOC定義:
<object name="EAS.Exam.DAL" assembly="EAS.Exam.DAL.SQLServer" type="EAS.Exam.DAL.SQLServer.DALManager" LifestyleType="Singleton" />
這樣我們就完成了對IDALManager與具體實例化對象完成了結偶,當然上例只是一個很簡單的例子,AgileEAS.NET中的IOC實現了構造注入和屬性注入,以下配置示例:
<object name="MasterDbConnection" assembly="EAS.Data" type="EAS.Data.Access.OleDbConnection" LifestyleType="Singleton">
<property name="ConnectionString" type="string" value="Provider=SQLOLEDB.1;Persist Security Info=False;User ID=sa;Password=sa;Initial Catalog=eas;Data Source=vm2003" />
</object>
<object name="OrmAccessor" assembly="EAS.Data" type="EAS.Data.ORM.OrmAccessor" LifestyleType="Singleton">
<property name="DbConnection" type="object" value="MasterDbConnection" />
</object>
<object name="CacheAccessor" assembly="EAS.Data" type="EAS.Data.ORM.CacheAccessor" LifestyleType="Singleton">
</object>
<object name="MasterDataAccessor" assembly="EAS.Data" type="EAS.Data.Access.OleDbAccessor" LifestyleType="Singleton">
<property name="Connection" type="object" value="MasterDbConnection" />
</object>
<object name="MasterRMIAccessor" assembly="EAS.Distributed.WebServiceClient" type="EAS.Distributed.WebServiceClient.RMIAccessor" LifestyleType="Singleton">
<constructor-arg index="0" type="string" value="http://demo.smarteas.net/activexform/Distributed/RMIService.asmx" />
</object>
對於IOC容器中的對象生存方式定義如下:
/// <summary>
/// 枚舉LifestyleType 組件的生存方式,即組件以何種生存周期在容器中生存。
/// </summary>
public enum LifestyleType
{
/// <summary>
/// Undefined,沒有定義生存周期,即以默認生存周期(Transient)。
/// </summary>
Undefined = 0x00000000,
/// <summary>
/// Singleton,組件一旦自在,則在所有的客商端中共享。
/// </summary>
Singleton = 0x00000001,
/// <summary>
/// Thread,每一個客戶端線程擁有單獨的一個實例。
/// </summary>
Thread = 0x00000002,
/// <summary>
/// Transient,組件在使用時創建、使用後銷毀。
/// </summary>
Transient = 0x00000004,
/// <summary>
/// Pooled,組件池,初始時分配一定數量的組件,客戶請求時,分配一個空閒組件,用戶使用完後交由池中。
/// </summary>
Pooled = 0x00000008
}
在使用中IOC提供了基於配置文件和程序配置兩種方式進行對象配置,IOC容器使用組件容器IContainer和IOC上下文環境IContext提供服務,IContainer定義如下:
IContainer
/// <summary>
/// 的組件容器,組件容器管理組件的生存,也是對外提供的一個接口。
/// </summary>
public interface IContainer : IDisposable
{
/// <summary>
/// 根據組件組件key向容器注冊組件實現。
/// </summary>
/// <param name="componentKey">組件key。</param>
void AddComponent(string componentKey);
/// <summary>
/// 根據組件組件key及組件實現類型向容器注冊組件實現。
/// </summary>
/// <param name="componentKey">組件key。</param>
/// <param name="componentImplementation"></param>
void AddComponent(string componentKey, Type componentImplementation);
/// <summary>
/// 根據組件key、接口類型及實現類型中注冊組件實現。
/// </summary>
/// <param name="componentKey">組件key。</param>
/// <param name="serviceType">組件接口類型。</param>
/// <param name="componentImplementation">組件實現類型。</param>
void AddComponent(string componentKey, Type serviceType, Type componentImplementation);
/// <summary>
/// 根據組件實現類型及組件接口類型向容器注冊組件實現。
/// </summary>
/// <param name="componentKey">組件key。</param>
/// <param name="componentImplementation">組件實現類型。</param>
/// <param name="serviceType">組件接口類型。</param>
/// <param name="lifestyleType"> 組件生命周期方式。</param>
/// <param name="lifestyleParameters"> 組件生命周期相關參數,參數為一個字符串,其中由“:”分隔。</param>
void AddComponent(string componentKey,Type serviceType,Type componentImplementation,Lifecycle.LifestyleType lifestyleType,string lifestyleParameters);
/// <summary>
/// 根據組件實現類型向容器注冊組件實現。
/// </summary>
/// <param name="componentImplementation">組件實現類型。</param>
void AddComponent(Type componentImplementation);
/// <summary>
/// 根據組件實現類型及組件接口類型向容器注冊組件實現。
/// </summary>
/// <param name="componentImplementation">組件實現類型。</param>
/// <param name="serviceType">組件接口類型。</param>
void AddComponent(Type componentImplementation,Type serviceType);
/// <summary>
/// 根據組件實例向組件容器中注冊組件。
/// </summary>
/// <param name="componentInstance">組件實例。</param>
void AddComponentInstance(object componentInstance);
/// <summary>
/// 根據組件key及組件實現向組件容器中注冊組件。
/// </summary>
/// <param name="componentKey">組件key。</param>
/// <param name="componentInstance">組件實例。</param>
void AddComponentInstance(string componentKey, object componentInstance);
/// <summary>
/// 根據組件key、接口類型及組件實例向組件容器中注冊組件實現。
/// </summary>
/// <param name="componentKey">組件key。</param>
/// <param name="serviceType">組件接口類型。</param>
/// <param name="componentInstance">組件實例。</param>
void AddComponentInstance(string componentKey, Type serviceType, object componentInstance);
/// <summary>
/// 根據組件key、接口類型、組件實例及組件生存類型向組件容器中注冊組件實現。
/// </summary>
/// <param name="componentKey">組件key。</param>
/// <param name="serviceType">組件接口類型。</param>
/// <param name="componentInstance">組件實例。</param>
/// <param name="lifestyleType"> 組件生命周期方式。</param>
/// <param name="lifestyleParameters"> 組件生命周期相關參數,參數為一個字符串,其中由“:”分隔。</param>
void AddComponentInstance(string componentKey, Type serviceType, object componentInstance,Lifecycle.LifestyleType lifestyleType,string lifestyleParameters);
/// <summary>
/// 根據組件key從組件容器中移除組件實現。
/// </summary>
/// <param name="componentKey">組件key。</param>
/// <returns></returns>
void RemoveComponent(string componentKey);
/// <summary>
/// 根據組件實例從組件容器中移除組件實現。
/// </summary>
/// <param name="componentInstance">組件實例。</param>
/// <returns></returns>
void RemoveComponent(object componentInstance);
/// <summary>
/// 根據組件key及組件實例從組件容器中移除組件實現。
/// </summary>
/// <param name="componentKey">組件key。</param>
/// <param name="componentInstance">組件實例。</param>
/// <returns></returns>
void RemoveComponent(string componentKey, object componentInstance);
/// <summary>
/// 根據組件key判斷組件容器是否含指定key的組件實例。
/// </summary>
/// <param name="componentKey">組件key。</param>
/// <returns></returns>
bool HasComponent(string componentKey );
/// <summary>
/// 根據組件實例判斷組件容器是否含指定key的組件實例。
/// </summary>
/// <param name="componentInstance">組件實例。</param>
/// <returns></returns>
bool HasComponent(object componentInstance );
/// <summary>
/// 根據組件接口類型判斷組件容器是否含指定key的組件實例。
/// </summary>
/// <param name="serviceType">組件接口類型。</param>
/// <returns></returns>
bool HasComponent( Type serviceType );
/// <summary>
/// 組件索引器,獲取指定Key值的組件實例。
/// </summary>
object this[string key]
{
get;
}
/// <summary>
/// 組件索引器,獲取指定接口類型的組件實例。
/// </summary>
object this[Type key]
{
get;
}
/// <summary>
/// 根據組件實例從組件容器中釋放組件實例。
/// </summary>
/// <param name="componentInstance">組件實例。</param>
void ReleaseComponent(object componentInstance );
/// <summary>
/// 根據組件Key從組件容器中釋放組件實例。
/// </summary>
/// <param name="componentKey">組件Key。</param>
void ReleaseComponent( string componentKey );
/// <summary>
/// 根據組件的key取得組件實例。
/// </summary>
/// <param name="componentKey">組件的key。</param>
/// <returns>組件實例。</returns>
object GetComponentInstance(string componentKey);
/// <summary>
/// 根據組件的類型取得組件實例。
/// </summary>
/// <param name="componentType">組件類型。</param>
/// <returns>組件實例。</returns>
object GetComponentInstance(Type componentType);
/// <summary>
/// 根據組件服務類型取得組件實例。
/// </summary>
/// <param name="serviceType">組件接口類型。</param>
/// <returns>組件實例。</returns>
object GetServiceComponentInstance(Type serviceType);
/// <summary>
/// 獲取一個值,批示容器中所有的組件列表。
/// </summary>
IDictionary<string, object> ComponentInstances { get; }
/// <summary>
/// 根據組件類型取得組件實例列表。
/// </summary>
/// <param name="serviceType">組件接口類型。</param>
/// <returns>組件實例列表。</returns>
IList GetComponentInstances(Type serviceType);
/// <summary>
/// 獲取一個值,該值批示組件容器中的所有組件適配器列表。
/// </summary>
IDictionary<string, IComponentAdapter> ComponentAdapters { get; }
/// <summary>
/// 根據組件key取得與組件相關的組件適配器。
/// </summary>
/// <param name="componentKey">組件的key。</param>
/// <returns>指定組件的組件適配器。</returns>
IComponentAdapter GetComponentAdapter(string componentKey);
/// <summary>
/// 根據組件類型取得與組件相關的組件適配器。
/// </summary>
/// <param name="componentType">組件類型。</param>
/// <returns>指定組件類型的組件適配器。</returns>
IComponentAdapter GetComponentAdapter(Type componentType);
/// <summary>
/// 根據組件類類型獲取組件適配器列表。
/// </summary>
/// <param name="serviceType">組件接口類型。</param>
/// <returns>指定組件類型的組件適配器列表。</returns>
IDictionary<string, IComponentAdapter> GetComponentAdapters(Type serviceType);
/// <summary>
/// 獲取一個值,該值批示組件容器中的所有組件生命周期管理器列表。
/// </summary>
IDictionary<string, ILifecycleManager> LifecycleManagers { get;}
/// <summary>
/// 根據組件key取得與組件相關的組件生命周期管理器。
/// </summary>
/// <param name="componentKey"> 組件的鍵。</param>
/// <returns>指定組件鍵的生命周期管理器。</returns>
Lifecycle.ILifecycleManager GetLifecycleManager(string componentKey);
/// <summary>
/// 根據組件實現類型取得與組件相關的組件生命周期管理器。
/// </summary>
/// <param name="componentType"> 組件的實現類型。</param>
/// <returns>指定組件類型的生命周期管理器。</returns>
Lifecycle.ILifecycleManager GetLifecycleManager(System.Type componentType);
/// <summary>
/// 根據組件接口類型取得與組件相關的組件生命周期管理器列表。
/// </summary>
/// <param name="serviceType"> 組件的接口類型。</param>
/// <returns>指定組件類型的生命周期管理器。</returns>
IDictionary<string, ILifecycleManager> GetLifecycleManagers(System.Type serviceType);
}
IContext定義:
IContext public interface IContext
{
/// <summary>
/// 組件容器,獲取系統上下文中的組件容器。
/// </summary>
EAS.Objects.IContainer Container { get;}
/// <summary>
/// 判定指定名稱的組件是生存周期是否為Singleton模式。
/// </summary>
/// <param name="name">組件的名稱。</param>
/// <returns>組件的生存周期是否為Singleton模式,是則返回true,否則返回false。</returns>
bool IsSingleton(string name);
/// <summary>
/// 根據組件名稱獲取指定組件的生命周期類型。
/// </summary>
/// <param name="name">組件的名稱。</param>
/// <returns>組件的生命周期類型。</returns>
Objects.Lifecycle.LifestyleType GetLifestyleType(string name);
/// <summary>
/// 上下文中是否包含指定名稱的組件實例。
/// </summary>
/// <param name="name">組件的名稱。</param>
/// <returns>是否包含特定的組件。包含則返回true,否則返回false。</returns>
bool ContainsObject(string name);
/// <summary>
/// 上下文中是否包含指定類型的組件實例。
/// </summary>
/// <param name="type">組件接口類型。</param>
/// <returns>是否包含特定的組件。包含則返回true,否則返回false。</returns>
bool ContainsObject(System.Type type);
/// <summary>
/// 索引器,根據名稱獲取指定的組件實例。
/// </summary>
object this[string name] { get; }
/// <summary>
/// 根據組件的名稱返回一個組件實例。
/// </summary>
/// <param name="name">組件的名稱。</param>
/// <returns>組件的實例。</returns>
object GetObject(string name);
/// <summary>
/// 根據組件的類型返回一個組件實例。
/// </summary>
/// <param name="type">組件的類型。</param>
/// <returns>組件的實例。</returns>
object GetObject(System.Type type);
/// <summary>
/// 根據組件的名稱返回組件實例的類型。
/// </summary>
/// <param name="name">組件名稱。</param>
/// <returns>組件類型。</returns>
Type GetType(string name);
/// <summary>
/// 在容器中配置組件。
/// </summary>
/// <param name="target">要配置的組件目標對象。</param>
void ConfigureObject(object target);
/// <summary>
/// 在容器中配置組件。
/// </summary>
/// <param name="name">組件名稱。</param>
void ConfigureObject(string name);
/// <summary>
/// 在容器中配置組件。
/// </summary>
/// <param name="target">要配置的組件目標對象。</param>
/// <param name="name">組件名稱。</param>
void ConfigureObject(object target, string name);
/// <summary>
/// 在容器中配置組件。
/// </summary>
/// <param name="type">組件類型。</param>
void ConfigureObject(System.Type type);
/// <summary>
/// 在容器中配置組件。
/// </summary>
/// <param name="type">組件類型</param>
/// <param name="name">組件名稱。</param>
void ConfigureObject(System.Type type,string name);
}