zoukankan      html  css  js  c++  java
  • 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方法根本不需要知道该类所应用的接口是谁,直接替换成工厂模式的需要知道抽象工厂接口

    上传下源码

  • 相关阅读:
    [poj解题]1017
    [算法] aov图拓扑算法
    【supervisord】部署单进程服务的利器
    【python】一个备份把文件备份到邮箱的python实现
    【GO】关于GO的浅显总结
    iOS开发快捷键
    iOS开发笔记
    VS2012智能提示无效解决方案
    国内几个WindowPhone广告平台
    纪念自己的第四个App:秘密Secret
  • 原文地址:https://www.cnblogs.com/zhijianliutang/p/2287345.html
Copyright © 2011-2022 走看看