Ioc最佳实践

      Ioc(依赖倒转)概念:不创建对象,但是描述创建它们的方式。在代码中不直接与对象和服务连接,但在配置文件中描述哪一个组件需要哪一项服务。容器负责将这些联系在一起。也就是说在项目中相关联类实例化的时候统一进行管理,客户端不需要关注类之间关联,只需要通过名称,就能获取实例化对象,记得在Pet shop中对于DAL层的实例是通过抽象工厂,通过客户端配置web.config文件反射得到,当然这样也能实现实例化对象的解耦,但是这种方式也有很多弊端,比如:反射性能、产品类复杂导致实例化麻烦等,Ioc就是解决这些问题,所以说Ioc是抽象工厂的升级。

参考院子(李会军)老师的文章,先把.net平台下的几种优秀的IOC框架做一个总结:

第一种:Castle

Castle中包含了一组开发框架,它里面的IOC容器是Windsor,目前Castle已经发布了RC1版本,其中Windsor已经是RC3了。在windsor中,提出了自动装配的概念,由容器来自动管理组件之间的依赖关系,无需用户去编写XML配置文件或者通过Attribute来指定容器之间的依赖关系。这样在使用伤非常简单,同样也带了一些问题,作为开发人员的我们无法控制组件依赖关系。如下面的xml配置文件,仅仅是设定了一个参数而已:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<components>
<component id="txtLog">
<parameters>
<target>log.txt</target>
</parameters>
</component>
</components>
</configuration>

简单使用:

声明一个日志接口:

using System;

namespace CastleIoc1
{
/// <summary>
/// 编写:Terrylee
/// 出处:http://terrylee.cnblogs.com
/// </summary>
public interface ILog
{
void Write(string MsgStr);
}
}

日志实现类,记录日志:

using System;

namespace CastleIoc1
{
/// <summary>
/// 编写:Terrylee
/// 出处:http://terrylee.cnblogs.com
/// </summary>
public class TextFileLog : ILog
{
private string _target;
private ILogFormatter _format;

public TextFileLog(string target,ILogFormatter format)
{
this._target = target;
this._format = format;
}

public void Write(string MsgStr)
{
string _MsgStr = _format.Format(MsgStr);
_MsgStr += _target;

//Output Message
Console.WriteLine("Output "+_MsgStr);
}
}
}

操作日志接口:

using System;
namespace CastleIoc1
{
/// <summary>
/// 编写:Terrylee
/// 出处:http://terrylee.cnblogs.com
/// </summary>
public interface ILogFormatter
{
string Format(string MsgStr);
}
}

操作日志实现类:

using System;

namespace CastleIoc1
{
/// <summary>
/// 编写:Terrylee
/// 出处:http://terrylee.cnblogs.com
/// </summary>
public class TextFormatter : ILogFormatter
{
public TextFormatter()
{

}

public string Format(string MsgStr)
{
return "[" + MsgStr + "]";
}
}
}

当我们客户端实例的时候,我们可以看到我们的日志实现类依赖者日志操作类,也就是说我们实例化的时候,需要先实例化日志操作类,然后传递给日志实现类,但是在Ioc中,我们解决的就是这个问题,实现这两个类的解耦,因为在日志实现类需要传入一个“日志地址”的参数,所以在BasicUsage.xml中定义该参数

using System;

using Castle.Windsor;
using Castle.Windsor.Configuration.Interpreters;

namespace CastleIoc1
{
/// <summary>
/// 编写:Terrylee
/// 出处:http://terrylee.cnblogs.com
/// </summary>
public class App
{
public static void Main()
{
//建立容器
IWindsorContainer container = new WindsorContainer( new XmlInterpreter("http://www.cnblogs.com/BasicUsage.xml") );

//加入组件
container.AddComponent( "txtLog",
typeof(ILog), typeof(TextFileLog) );

container.AddComponent( "format",
typeof(ILogFormatter), typeof(TextFormatter) );

//获取组件
ILog log = (ILog) container["txtLog"];

//使用组件
log.Write("First Castle IOC Demo");

Console.ReadLine();
}
}
}

这样我们就能实现两个类的解耦,使用的时候,只需要从container中获取强制转换下就行。这里有一点需要记住,我们添加的组件的时候,我们在xml文件中定义的ID名称已经要和我们添加的名称相同,如上面的txtLog..

第二种:Spring.Net

Sping.Net是从Java的Spring Framework移植过来的,现在的版本应该是Spring.NET 1.0.2,正好和前面说的Casle相反,Spring.Net推崇的做法是使用配置文件来管理组件之间的依赖关系,当然它支持自动装配,不过不推荐使用。这样配置文件的方式,带来的问题是当我们的项目非常大的时候,配置文件非常的繁琐,手工配置会变的很复杂。需要指定每一个组件以及他们之间的依赖关系。

新建接口,个人信息操作

using System;
namespace Spring.net
{
public interface IPersonInfo
{
string save();
}
}

个人信息操作实现类

using System;

namespace Spring.net
{
public class PersonInfo : IPersonInfo
{
public string save()
{
return ("您已经保存了个人信息");
}
}
}

个人信息操作接口:

using System;


namespace Spring.net
{
public interface IpersonInfoManger
{
void MyManger(string _name, IPersonInfo _Iperson);
}
}

个人信息操作实现类:

using System;

namespace Spring.net
{
public class personInfoManger:IpersonInfoManger
{
public void MyManger(string _name, IPersonInfo _Iperson)
{
Console.WriteLine(string.Format("{0}对信息进行了保存:{1}",_name,_Iperson.save()));
}
}
}

在app.config中配置我们的这两个方法:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>

<configSections>
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
</sectionGroup>
</configSections>



<spring>
<context>
<resource uri="config://spring/objects" />
</context>
<objects xmlns="http://www.springframework.net">

<object id="myObject" type="Spring.net.PersonInfo, Spring.net" singleton="true">
</object>

<object id="myObject2" type="Spring.net.personInfoManger, Spring.net" singleton="true">
</object>

</objects>
</spring>
</configuration>

看客户端实现方法:

using System;

using Spring.Context.Support;
using Spring.Context;

namespace Spring.net
{
class Program
{
static void Main(string[] args)
{
//普通方法
IpersonInfoManger IIM = new personInfoManger();
IIM.MyManger("超人", new PersonInfo());


//IOC方法
IApplicationContext ctx = ContextRegistry.GetContext();
IPersonInfo dao = ctx.GetObject("myObject") as IPersonInfo;
IpersonInfoManger infoManger = ctx.GetObject("myObject2") as IpersonInfoManger;
if (dao != null)
{
Console.WriteLine("----------------------------");
infoManger.MyManger("超人2", dao);
}

Console.ReadLine();

}
}
}

至此已经是实现了一个spring.net的简单的Ioc应用。

第三种,微软的Unity实现,作为轻量级的开发模型,微软肯定也是不甘落后的,下面看一下在Unity下该如何配置IOC应用。

先下载Unity类库:http://www.microsoft.com/downloads/details.aspx?FamilyId=2d24f179-e0a6-49d7-89c4-5b67d939f91b&displaylang=en

项目中添加引用:

简单的设计一个模型,一个IMan(人类)接口,一个IWeapon(武器)接口,很显然这两者是耦合在一起的,我们通IOC对两者进行解耦

看设计图

看几个关键类:

using System;
using System.Text;

namespace UnityMyDemo
{
public class AmericaMan:IMan
{
#region IMan 成员

private IWeapon myWeapon;
public AmericaMan(IWeapon _Weapon)
{
myWeapon = _Weapon;
}
public string GetName()
{
return "美国人武器" + myWeapon.Atter();
}

#endregion
}
}

同样在config文件中对相关联的类进行配置:

<?xml version="1.0"?>
<configuration>

<configSections>
<section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
Microsoft.Practices.Unity.Configuration"/>
</configSections>

<!--unity声明段,加入xmlns后vs会下载语法规范并语法提示-->
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">

<alias alias="singleton" type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager,
Microsoft.Practices.Unity"/>
<alias alias="external" type="Microsoft.Practices.Unity.ExternallyControlledLifetimeManager,
Microsoft.Practices.Unity"/>

<namespace name="UnityMyDemo"/>
<!--命名空间-->
<assembly name="UnityMyDemo"/>
<!--程序集名称-->

<container name="myContaion">
<register type="IWeapon" mapTo="Gun" name="AmericaWeapon"/>
<!--声明类型映射-->
<register type="IWeapon" mapTo="Sword" name="chinaWeapon"/>
<!--声明类型映射-->
<register type="IMan" mapTo="ChinaMan" name="ChinaManFactory">
<lifetime type="singleton"></lifetime>
<!--生命周期为单例-->
<constructor>
<!--构造注入-->
<param name="_Weapon">
<!--构造函数参数-->
<dependency name="chinaWeapon"/>
<!--自动匹配类型-->
</param>
</constructor>
</register>

<register type="IMan" mapTo="AmericaMan" name="AmericaManFactory">
<lifetime type="singleton"></lifetime>
<!--生命周期为单例-->
<constructor>
<!--构造注入-->
<param name="_Weapon">
<!--构造函数参数-->
<dependency name="AmericaWeapon"/>
<!--自动匹配类型-->
</param>
</constructor>
</register>
</container>

</unity>
<startup>

<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup>
</configuration>

文档很清楚..不做解释..需要说明点就是可以在这里直接声明unity结点,而代替代码的注册

看应用类:

   class Program
{
static void Main(string[] args)
{
//传统用法
Console.WriteLine("\n普通方法注册");
IWeapon Weapon = new Sword();
IMan Man = new ChinaMan(Weapon);
Console.WriteLine(Man.GetName());

Weapon = new Gun();
Man = new AmericaMan(Weapon);
Console.WriteLine(Man.GetName());

Console.WriteLine("\nIOC方法注册");
//IOC方法
Console.WriteLine(IOCHelper.Get("myContaion").Resolve<ChinaMan>("ChinaManFactory").GetName());
Console.WriteLine(IOCHelper.Get("myContaion").Resolve<AmericaMan>("AmericaManFactory").GetName());
Console.Read();

}


}

可以看到的是IOC方法根本不需要知道该类所应用的接口是谁,直接替换成工厂模式的需要知道抽象工厂接口

上传下源码

 

posted @ 2011-12-14 11:24  指尖流淌  阅读(702)  评论(0编辑  收藏  举报