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="configDI.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之外还有一些其它用途,比如:实现单件模式(而且这种实现方式更灵活,比如我们可以让任何一个普通的类,在容器的生命周期内仅返回一个实例,这是传统的单件模式中"把类硬编码定死为单件实例"无法做到的)
- 【Code】关关的刷题日记22——Leetcode 53. Maximum Subarray
- 【Java学习笔记之三十四】超详解Java多线程基础
- Codeforces 842B Gleb And Pizza【几何,水】
- Python3希尔排序
- Codeforces 842A Kirill And The Game【暴力,水】
- Wannafly模拟赛 A.矩阵(二分答案+hash)
- 【Java数据结构学习笔记之一】线性表的存储结构及其代码实现
- Comparison of Apache Stream Processing Frameworks: Part 1
- 【LeetCode】关关的刷题日记23——Leetcode 66. Plus One
- Codeforces Round #434 (Div. 2, based on Technocup 2018 Elimination Round 1)&&Codeforces 861A k-roun
- 【Java数据结构学习笔记之二】Java数据结构与算法之栈(Stack)实现
- 【Java数据结构学习笔记之三】Java数据结构与算法之队列(Queue)实现
- Comparison of Apache Stream Processing Frameworks: Part 2
- 2017 Multi-University Training Contest - Team 9 1005&&HDU 6165 FFF at Valentine【强联通缩点+拓扑排序】
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- SpringBoot 2.3.0 新特性一览,快来跟我实践一波!
- 【腾讯】在前端开发中,如何获取浏览器的唯一标识
- 如何实现表格单双行条纹样式
- Angular 容易忽略的知识点
- 语雀自动同步到hexo博客
- 推荐 3 款超好用的 Docker 图形化管理工具
- python标准库之glob介绍
- Python 为什么只需一条语句“a,b=b,a”,就能直接交换两个变量?
- 使用List中的remove方法遇到的坑,不信你没有踩过!
- python opencv 图像尺寸变换
- OpenCv保存图像
- 机器学习|KNN
- docker 查看容器日志
- consul配置ACL
- CentOS7.5更改python版本后及yum不能用的解决办法,非编译!