1.引言
高内聚,低耦合成为一个OO架构设计的一个参考标准。高内聚是一个模块或者一个类中成员跟这个模块或者类的关系尽量高,低耦合是不同模块或者不同类之间关系尽量简单。
拿咱国家举例来说,假如你是中国人。
高内聚:就是说你跟中国亲,关系好,国家会保护你。
低内聚:就是说你跟中国的关系不好,那还怎么混,改天就要*你,你就是个问题源。
低耦合:就是说你跟日本的关系非常正常,非常简单,这样的话,就不会被骂汉奸了。
高耦合:就是说你跟日本亲,活该被砸,被游街。
上面例子虚构的,不太贴切,但从中可以看出来高内聚和低耦合的处境是最好的。高内聚是对内部成员跟本身这个模块的关系的描述,低耦合是对成员跟外部模块之间关系的描述。对内对外也是一个相对范围,一个模块里面的小模块之间是耦合,对大模块是聚合,所以说耦合无处不在,我们都要低耦合,Untity就可以帮助我们。
2.Unity
Unity是一个IoC容器,用来实现依赖注入(Dependency Injection,DI),减少耦合的,Unity出自于伟大的微软。对依赖注入和IoC模式可以查看之前一篇文章IoC模式。
unity组件网址:http://unity.codeplex.com/
网址中有源码有文档有示例,大家可以下载。我是用的是2.1版本。
看看Unity能做些什么,列举部分如下:
1.Unity支持简单对象创建,特别是分层对象结构和依赖,以简化程序代码。其包含一个编译那些可能存在依赖于其他对象的对象实例机制。
2.Unity支持必要的抽象,其允许开发者在运行时或配置去指定依赖关系同时可以简单的管理横切点(AOP)。
3.Unity增加了推迟到容器组件配置的灵活性。其同样支持一个容器层次的结构。
4.Unity拥有服务定位能力,对于一个程序在许多情况下重复使用组件来分离和集中功能是非常有用的。
5.Unity允许客户端储存或缓存容器。对于在ASP.NET Web applications中开发者将容器持久化于ASP.NET中的session或application中特别有效。
6.Unity拥有拦截能力,其允许开发者通过创建并执行handlers(在方法或属性被调用到达之前)来为已存在的组件增加一个函数,并再次为返回调用结果。
7.Unity可以从标准配置系统中读取配置信息,例如:XML文件,同时使用配置文件来配置容器。
8.Unity支持开发者实现自定义容器扩展,例如:你可以实现方法来允许额外的对象构造和容器特征,例如缓存。
9.Unity允许架构师和开发者在现代化的程序中更简单的实现通用设计模式。
.....
我们项目中什么时候要使用到Unity呢,如下情况:
1.所构建的系统依赖于健全的面向对象原则,但是大量不同的代码交织在一起而难以维护。
2.构建的对象和类需要依赖其他对象或类。
3.依赖于复杂的或需要抽象的对象。
4.希望利用构造函数、方法或属性的调用注入优势。
5.希望管理对象实例的生命周期。
6.希望能够在运行时管理并改变依赖关系。
7.希望在拦截方法或属性调用的时候生成一个策略链或管道处理容器来实现横切(AOP)任务。
8.希望在Web Application中的回发操作时能够缓存或持久化依赖关系。
..............
先看看Unity容器IUnityContainer 接口的定义:
Code //Interface defining the behavior of the Unity dependency injection container.
public interface IUnityContainer : IDisposable
{
//The parent of this container.
IUnityContainer Parent { get; } //Get a sequence of Microsoft.Practices.Unity.ContainerRegistration that describe
//the current state of the container.
IEnumerable<ContainerRegistration> Registrations { get; } //Add an extension object to the container.
IUnityContainer AddExtension(UnityContainerExtension extension); //Run an existing object through the container and perform injection on it.
object BuildUp(Type t, object existing, string name, params ResolverOverride[] resolverOverrides); //Resolve access to a configuration interface exposed by an extension.
object Configure(Type configurationInterface); //Create a child container.
IUnityContainer CreateChildContainer(); //Register an instance with the container.
IUnityContainer RegisterInstance(Type t, string name, object instance, LifetimeManager lifetime); //Register a type mapping with the container, where the created instances will
//use the given Microsoft.Practices.Unity.LifetimeManager.
IUnityContainer RegisterType(Type from, Type to, string name, LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers); //Remove all installed extensions from this container.
IUnityContainer RemoveAllExtensions(); //Resolve an instance of the requested type with the given name from the container.
object Resolve(Type t, string name, params ResolverOverride[] resolverOverrides); //Return instances of all registered types requested.
IEnumerable<object> ResolveAll(Type t, params ResolverOverride[] resolverOverrides); //Run an existing object through the container, and clean it up.
void Teardown(object o);
}
IUnityContainer 中有几个方法经常会使用到,如:RegisterInstance,RegisterType,Resolve等等。
Unity为了方便操作,专门为IUnityContainer 提供了许多的扩展方法,部分方法声明如:
Code/// <summary>
/// 扩展方法 v2.0.50727
/// </summary>
public static class UnityContainerExtensions
{
public static IUnityContainer AddNewExtension<TExtension>(this IUnityContainer container) where TExtension : UnityContainerExtension;
public static T BuildUp<T>(this IUnityContainer container, T existing, params ResolverOverride[] resolverOverrides);
public static T BuildUp<T>(this IUnityContainer container, T existing, string name, params ResolverOverride[] resolverOverrides);
public static object BuildUp(this IUnityContainer container, Type t, object existing, params ResolverOverride[] resolverOverrides);
public static TConfigurator Configure<TConfigurator>(this IUnityContainer container) where TConfigurator : IUnityContainerExtensionConfigurator;
public static bool IsRegistered<T>(this IUnityContainer container);
public static bool IsRegistered<T>(this IUnityContainer container, string nameToCheck);
public static bool IsRegistered(this IUnityContainer container, Type typeToCheck);
public static bool IsRegistered(this IUnityContainer container, Type typeToCheck, string nameToCheck);
public static IUnityContainer RegisterInstance<TInterface>(this IUnityContainer container, TInterface instance);
public static IUnityContainer RegisterInstance<TInterface>(this IUnityContainer container, string name, TInterface instance);
public static IUnityContainer RegisterInstance<TInterface>(this IUnityContainer container, TInterface instance, LifetimeManager lifetimeManager);
public static IUnityContainer RegisterInstance(this IUnityContainer container, Type t, object instance);
public static IUnityContainer RegisterInstance<TInterface>(this IUnityContainer container, string name, TInterface instance, LifetimeManager lifetimeManager);
public static IUnityContainer RegisterInstance(this IUnityContainer container, Type t, object instance, LifetimeManager lifetimeManager);
public static IUnityContainer RegisterInstance(this IUnityContainer container, Type t, string name, object instance);
public static IUnityContainer RegisterType<T>(this IUnityContainer container, params InjectionMember[] injectionMembers);
public static IUnityContainer RegisterType<TFrom, TTo>(this IUnityContainer container, params InjectionMember[] injectionMembers) where TTo : TFrom;
public static IUnityContainer RegisterType<T>(this IUnityContainer container, LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers);
public static IUnityContainer RegisterType<TFrom, TTo>(this IUnityContainer container, LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers) where TTo : TFrom;
public static IUnityContainer RegisterType<TFrom, TTo>(this IUnityContainer container, string name, params InjectionMember[] injectionMembers) where TTo : TFrom;
public static IUnityContainer RegisterType<T>(this IUnityContainer container, string name, params InjectionMember[] injectionMembers);
public static IUnityContainer RegisterType(this IUnityContainer container, Type t, params InjectionMember[] injectionMembers);
public static IUnityContainer RegisterType<T>(this IUnityContainer container, string name, LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers);
public static IUnityContainer RegisterType<TFrom, TTo>(this IUnityContainer container, string name, LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers) where TTo : TFrom;
public static IUnityContainer RegisterType(this IUnityContainer container, Type t, LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers);
public static IUnityContainer RegisterType(this IUnityContainer container, Type t, string name, params InjectionMember[] injectionMembers);
public static IUnityContainer RegisterType(this IUnityContainer container, Type from, Type to, params InjectionMember[] injectionMembers);
public static IUnityContainer RegisterType(this IUnityContainer container, Type t, string name, LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers);
public static IUnityContainer RegisterType(this IUnityContainer container, Type from, Type to, LifetimeManager lifetimeManager, params InjectionMember[] injectionMembers);
public static IUnityContainer RegisterType(this IUnityContainer container, Type from, Type to, string name, params InjectionMember[] injectionMembers);
public static T Resolve<T>(this IUnityContainer container, params ResolverOverride[] overrides);
public static T Resolve<T>(this IUnityContainer container, string name, params ResolverOverride[] overrides);
public static object Resolve(this IUnityContainer container, Type t, params ResolverOverride[] overrides);
public static IEnumerable<T> ResolveAll<T>(this IUnityContainer container, params ResolverOverride[] resolverOverrides); public static IUnityContainer LoadConfiguration(this IUnityContainer container);
public static IUnityContainer LoadConfiguration(this IUnityContainer container, string containerName);
public static IUnityContainer LoadConfiguration(this IUnityContainer container, UnityConfigurationSection section);
public static IUnityContainer LoadConfiguration(this IUnityContainer container, UnityConfigurationSection section, string containerName);
}
下面来个简单的例子,现在项目中添加Microsoft.Practices.Unity.dll和Microsoft.Practices.Unity.Configuration.dll的引用,准备几个类,如下:
Code/// <summary>
/// 班级接口
/// </summary>
public interface IClass
{
string ClassName { get; set; } void ShowInfo();
}
/// <summary>
/// 计科班
/// </summary>
public class CbClass : IClass
{
public string ClassName { get; set; } public void ShowInfo()
{
Console.WriteLine("计科班:{0}", ClassName);
}
}
/// <summary>
/// 电商班
/// </summary>
public class EcClass : IClass
{
public string ClassName { get; set; } public void ShowInfo()
{
Console.WriteLine("电商班:{0}", ClassName);
}
}
用编程方式实现注入:
Codepublic static void ContainerCodeTest1()
{
IUnityContainer container = new UnityContainer(); //默认注册(无命名),如果后面还有默认注册会覆盖前面的
container.RegisterType<IClass, CbClass>(); //命名注册
container.RegisterType<IClass, EcClass>("ec"); //解析默认对象
IClass cbClass = container.Resolve<IClass>();
cbClass.ShowInfo(); //指定命名解析对象
IClass ecClass = container.Resolve<IClass>("ec");
ecClass.ShowInfo(); //获取容器中所有IClass的注册的已命名对象
IEnumerable<IClass> classList = container.ResolveAll<IClass>();
foreach (var item in classList)
{
item.ShowInfo();
}
}
配置文件方式:
Code<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/>
</configSections>
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
<!--定义类型别名-->
<aliases>
<add alias="IClass" type="ConsoleApplication1.UnityDemo.IClass,ConsoleApplication1" />
<add alias="CbClass" type="ConsoleApplication1.UnityDemo.CbClass,ConsoleApplication1" />
<add alias="EcClass" type="ConsoleApplication1.UnityDemo.EcClass,ConsoleApplication1" />
</aliases>
<!--容器-->
<container name="FirstClass">
<!--映射关系-->
<register type="IClass" mapTo="CbClass"></register>
<register type="IClass" name="ec" mapTo="EcClass"></register>
</container>
</unity>
</configuration>
Codepublic static void ContainerConfigurationTest1()
{
IUnityContainer container = new UnityContainer();
string configFile = "http://www.cnblogs.com/UnityDemo/Constructor/Unity.config";
var fileMap = new ExeConfigurationFileMap { ExeConfigFilename = configFile };
//从config文件中读取配置信息
Configuration configuration =
ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
//获取指定名称的配置节
UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity"); //载入名称为FirstClass 的container节点
container.LoadConfiguration(section, "FirstClass"); //解析默认对象
IClass cbClass = container.Resolve<IClass>();
cbClass.ShowInfo(); //指定命名解析对象
IClass ecClass = container.Resolve<IClass>("ec");
ecClass.ShowInfo(); //获取容器中所有IClass的注册的已命名对象
IEnumerable<IClass> classList = container.ResolveAll<IClass>();
foreach (var item in classList)
{
item.ShowInfo();
}
}
效果跟代码方式一样
Unity使用方式基本分为三步:
- 声明容器IUnityContainer
- Register注册类型
- Resolve解析类型对象
3.小结
看到IUnityContainer接口声明还是比较简单的,主要用到的方法也不多,另外提供了扩展方法,看起来代码挺多,都是一些方法重载,不要对Unity组建感到恐惧,我们只是简单的使用它,主要是使用IUnityContainer。