Unity Application Block 1.2 学习笔记

昨天花了一天时间,把IOC/DI的相关文章以及Unity相关的一些文章基本在园子里搜了个遍

先给出几篇不错的文章链接:

Unity Application Block官方网址 http://www.codeplex.com/unity

吕震宇整理的[Object Builder Application Block] http://www.cnblogs.com/zhenyulu/articles/641728.html

吕震宇[你真的了解Ioc与AOP吗?] http://www.cnblogs.com/zhenyulu/articles/233966.html

坚强2002翻译的[Inversion of Control Containers and the Dependency Injection pattern] http://www.cnblogs.com/me-sa/archive/2008/07/30/IocDI.html

赤脚小子的[unity系列] http://www.cnblogs.com/kebixisimba/archive/2008/05/19/1202467.html NEE's [Unity 配置:typeConverter的使用] http://www.cnblogs.com/nickyao/archive/2008/05/04/1181804.html

Warmth & Chilliness的[Unity -- .NET下的原生Ioc框架,让一部分人先用起来] http://www.cnblogs.com/think8848/archive/2008/10/25/1319616.html

基本上把上面的这些个文章全耐着性子看完,相关知识点的“扫盲”工作也差不多完成了

这里只是把我练习的一个例子贴在这里,并发表一些个人粗浅的看法

应用场景:随便给一些数字,要求对这些数字进行一项基本的数据运算(例子中只实现了加法/乘法)

先添加对Microsoft.Practices.Unity.dll的引用

准备测试用的接口和类:

/// <summary>
 /// 接口
 /// </summary>
 public interface Icalculate
    {
 int Calculate(params int[] a);

 double Calculate(params double[] a);

 string GetOperationName();

 
    }

 /// <summary>
 /// 加法运算
 /// </summary>
 public class Addtive : Icalculate
    {
 /// <summary>
 /// 注意:至少要有一个构造函数,否则用配置文件方式Resolve<Icalculate>时会提示:Icalculate是一个接口,没有构造函数,所以不能创建实例云云,但有趣的是用硬编码方式却可以成功
 /// </summary>
 public Addtive() { }

 public int Calculate(params int[] a)
        {
 int Result = 0;

 foreach (int x in a)
            {
                Result += x;
            }

 return Result;
        }

 public double Calculate(params double[] a)
        {
 double Result = 0.0;

 foreach (double x in a)
            {
                Result += x;
            }

 return Result;
        }

 public string GetOperationName()
        {
 return "加法";
        }
    }

 /// <summary>
 /// 乘法运算
 /// </summary>
 public class Multiplication : Icalculate
    {

 public Multiplication() { }

 public int Calculate(params int[] a)
        {
 int Result = 1;

 foreach (int x in a)
            {
                Result *= x;
            }

 return Result;
        }

 public double Calculate(params double[] a)
        {
 double Result = 1.0;

 foreach (double x in a)
            {
                Result *= x;
            }

 return Result;
        }

 public string GetOperationName()
        {
 return "乘法";
        }
    }

 /// <summary>
 /// (四则)运算管理器
 /// </summary>
 public class CalcManager
    {
 private Icalculate _calc;


 public CalcManager(Icalculate IC)
        {
            _calc = IC;
        }

 //[InjectionMethod]
 //public void SetCalculate(Icalculate IC) {
 //    _calc = IC;
 //}

 public void Compute(params int[] a)
        {
 string _paramName = "";

 foreach (int x in a)
            {
                _paramName += x.ToString() + ",";
            }
            _paramName = _paramName.Trim(',');

            Console.WriteLine("{0} {1}计算结果:{2}", _paramName, _calc.GetOperationName(), _calc.Calculate(a));
        }

 public void Compute(params double[] a)
        {
 string _paramName = "";

 foreach (double x in a)
            {
                _paramName += x.ToString() + ",";
            }
            _paramName = _paramName.Trim(',');

            Console.WriteLine("{0} {1}计算结果:{2}", _paramName, _calc.GetOperationName(), _calc.Calculate(a));
        }

    }

为了对比,我们先用传统方式来调用试下:

static void Main(string[] args)
{
 #region 不用依赖注入的传统方式
    CalcManager CM = new CalcManager(new Addtive());
    CM.Compute(1, 2, 3, 4, 5);//计算1,2,3,4,5的和

 //CM = new CalcManager(new Multiplication());
 //CM.Compute(1, 2, 3, 4, 5);//计算1,2,3,4,5的乘积
 #endregion 

    Console.ReadLine();
}

虽然简单易懂,但细想一下可扩展性并不高,如果以后又增加了除法,平方,减法...等一系列算法,不是每次都要这一段代码吗?原因就是接口,算法实体类,调用程序之间的耦合性太高

接下来,我们用Unity换一种写法:

using System;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using System.Configuration;

static void Main(string[] args)
{
 

 #region 使用依赖注入(硬编码方式)
    IUnityContainer container = new UnityContainer();
    container.RegisterType<Icalculate, Addtive>() //注入加法类
         .RegisterType<CalcManager>();//注入管理器            


    CalcManager CM = container.Resolve<CalcManager>();//取得CalcManager的实例
    CM.Compute(1.1, 2.9, 3.1, 4, 5);

 //container.RegisterType<Icalculate, Multiplication>();//继续注入乘法类

 //CM = container.Resolve<CalcManager>();
 //CM.Compute(1, 2, 3, 4, 5);
 #endregion

 

    Console.ReadLine();
}

单从代码上看,只不过换了种写法和思路,但仍然属于“硬编码”的方式,如果要增加其它算法或换成其它算法,一样还是要改这段代码.(貌似纯属瞎折腾?呵呵)

下面切入正题,Unity除了这种硬编码方式,还允许把注入规则/映射写到配置文件里

先修改App.Config,内容大致如下:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
 <configSections>
 <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration, Version=1.2.0.0, Culture=neutral" />
 </configSections>
 <unity configSource="config\DI.config" />
</configuration>

同时再新建一个config目录,把DI.config文件放在该目录下,内容:

<?xml version="1.0" ?>
<unity>
 <typeAliases>
 <typeAlias alias="ICalc" type="UnityStudy.Icalculate, UnityStudy" />
 <typeAlias alias="Add" type="UnityStudy.Addtive, UnityStudy" />
 <typeAlias alias="Mul" type="UnityStudy.Multiplication, UnityStudy" />
 <typeAlias alias="CM" type="UnityStudy.CalcManager, UnityStudy" />
 </typeAliases>
 <containers>
 <container>
 <types>
 <type type="ICalc" mapTo="Mul"/> 
 <!--结实验,下面这一行加不加程序都能运行,只要确保CalcManager中有一个参数为Icalculate的构架函数或(注入)设置方法就行[参看CalcManager中注释掉的部分],Unity在这一点上确实比较“智能”-->
 <type type="CM"/> 
 </types>
 </container>
 </containers>
</unity>

调用代码再换一种写法:

static void Main(string[] args)
{
 
 #region 使用依赖注入(配置文件方式)
    IUnityContainer container = new UnityContainer();
    UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity");
    section.Containers.Default.Configure(container);

    CalcManager CM = container.Resolve<CalcManager>();
    CM.Compute(1, 2, 3, 4, 5);
 #endregion

    Console.ReadLine();
}

这回仔细看下,代码中已经完全找不到Addtive,Multiplication等这些具体的类名了,整个程序完全依赖于配置文件中的相关节点(其实OO的角度来讲,是基于接口Icalculate的编程以及不同对象的组合让这一切成为可能)。

如果我们要把乘法运算换成加法运算,太容易了,把DI.config中的

<type type="ICalc" mapTo="Mul"/>   

换成

<type type="ICalc" mapTo="Add"/>

原来的调用代码一行都不用改!

最后:Unity除了实现IOC/DI之外还有一些其它用途,比如:实现单件模式(而且这种实现方式更灵活,比如我们可以让任何一个普通的类,在容器的生命周期内仅返回一个实例,这是传统的单件模式中"把类硬编码定死为单件实例"无法做到的)

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏菜鸟前端工程师

JavaScript学习笔记025-闭包0缓存计算0console属性

11730
来自专栏恰童鞋骚年

设计模式的征途—5.原型(Prototype)模式

相信大多数的人都看过《西游记》,对孙悟空拔毛变出小猴子的故事情节应该都很熟悉。孙悟空可以用猴毛根据自己的形象复制出很多跟自己一模一样的小猴兵出来,其实在设计模式...

11930
来自专栏大内老A

ASP.NET MVC下的四种验证编程方式

ASP.NET MVC采用Model绑定为目标Action生成了相应的参数列表,但是在真正执行目标Action方法之前,还需要对绑定的参数实施验证以确保其有效性...

23870
来自专栏跟着阿笨一起玩NET

跨线程调用窗体控件

本文转载:http://www.csharpwin.com/csharpspace/11279r6763.shtml

33910
来自专栏安恒网络空间安全讲武堂

赛前福利②最新2018HITB国际赛writeup

FIRST 距离“西湖论剑杯”全国大学生网络空间安全技能大赛只有9天啦! 要拿大奖、赢offer,那必须得来点赛前练习定定心啊~这不,讲武堂就拿到了2018HI...

34740
来自专栏海纳周报

用Atomic实现锁

一直想写ReentrantLock,就得先介绍AbstractQueueSynchronizer,可是我觉得这样写,不过瘾,我把代码贴一遍,懂的人自己就能找到这...

37260
来自专栏技术博客

编写高质量代码改善C#程序的157个建议[避免finaly内的无效代码、避免嵌套异常、避免吃掉异常、注意循环异常处理]

  本文已同步到http://www.cnblogs.com/aehyok/p/3624579.html。本文主要来学习以下几点建议

11410
来自专栏有趣的django

PYTHON面试

大部分的面试问题,有最近要找事的老铁吗?  python语法以及其他基础部分 可变与不可变类型;  浅拷贝与深拷贝的实现方式、区别;deepcopy如果你来...

75870
来自专栏贾老师の博客

Lock-Free 学习总结

在通常使用 Mutex 互斥锁的场景, 有的线程抢占了锁, 其他线程则会被阻塞, 当获得锁的进程挂掉之后, 整个程序就 block 住了. 但在 Lock-Fr...

79840
来自专栏Android群英传

Android multidex 主dex是怎么来的?

47820

扫码关注云+社区

领取腾讯云代金券