以下为DI控制反转个人理解烦请各位大牛指教~

编写程序时我们应当遵循抵耦合高内聚的原则(各个功能模块互不依赖).

我们可以利用面向对象里面接口的特性来进行DI控制反转,让功能模块全部依赖接口,而不依赖具体的实现类,当程序跑起来以后通过注入的方式注入具体的实现类如以下代码:

  /// <summary>
/// 购物车类
/// </summary>
public class ShoppingCart {
/// <summary>
/// 创建计算器接口
/// </summary>
IvalueCalculator calculator; /// <summary>
/// 构造函数来注入实际调用的计算方法
/// </summary>
/// <param name="ivalueCalculator"></param>
public ShoppingCart(IvalueCalculator ivalueCalculator)
{
calculator = ivalueCalculator;
} /// <summary>
/// 价格计算
/// </summary>
/// <returns></returns>
public decimal CalculateStockValue()
{
Product[] products = {
new Product {Name = "西瓜", Category = "水果", Price = 2.3M},
new Product {Name = "苹果", Category = "水果", Price = 4.9M},
new Product {Name = "空心菜", Category = "蔬菜", Price = 2.2M},
new Product {Name = "地瓜", Category = "蔬菜", Price = 1.9M}
};
decimal totalValue = calculator.ValueProducts(products);
return totalValue;
} } /// <summary>
/// 计算器实现类
/// </summary>
public class LinqValueCalculator : IvalueCalculator
{
/// <summary>
/// 价格计算实现方法
/// </summary>
/// <param name="products"></param>
/// <returns></returns>
public decimal ValueProducts(params Product[] products)
{
return products.Sum(u => u.Price);
} } /// <summary>
/// 计算器接口
/// </summary>
public interface IvalueCalculator
{
/// <summary>
/// 价格计算方法
/// </summary>
/// <param name="products"></param>
/// <returns></returns>
decimal ValueProducts(params Product[] products);
}

这样,购物车类就实现了松耦合,购物车内的计算价格方法只依赖于计算器接口(IvalueCalculator ),而不依赖具体的计算类(LinqValueCalculator),实际的价格计算类我们通过构造函数的方法注入到购物车内的计算器接口

当我们在实际使用时既可以像如下方法一样实现

static void Main(string[] args)
{
//创建一个接口的对象,引用计算类
IvalueCalculator calculator = new LinqValueCalculator();
//以方法传入具体实现类
ShoppingCart shopping = new ShoppingCart(calculator);
        //调用
Console.WriteLine("价格:{0}", shopping.CalculateStockValue());
Console.ReadLine();
}

可以通过C#的 Ninject 来管理各种注入,只需要提前绑定好接口的对应实现类既可以在使用时去索要一个对应的实现类,如下代码

     //Ninject
IKernel ninjectKernel = new StandardKernel();
//把一个接口(IValueCalculator)绑定到一个实现该接口的类(LinqValueCalculator)
ninjectKernel.Bind<IvalueCalculator>().To<LinqValueCalculator>(); //向NiNject索要一个IvalueCalculator的实现类
IvalueCalculator calcImpl = ninjectKernel.Get<IvalueCalculator>();
//注入购物车类
ShoppingCart shopping = new ShoppingCart(calcImpl); Console.WriteLine("价格:{0}", shopping.CalculateStockValue());
Console.ReadLine();

知识点1:并且,如果你的价格计算实现类(LinqValueCalculator)的内部调用了其它接口,那么Ninject会自动帮你注入要调用接口的实现类(前提是这个调用的接口在之前已经绑定了实现类)

例如:创建一个打折接口(IDiscountHelper),再创建一个类来实现一个默认打折方法(DefaultDiscountHelper)

    /// <summary>
/// 折扣计算接口
/// </summary>
public interface IDiscountHelper {
decimal ApplyDiscount(decimal totalParam);
} /// <summary>
/// 默认折扣计算接口
/// </summary>
public class DefaultDiscountHelper : IDiscountHelper
{
/// <summary>
/// 折扣结算方法
/// </summary>
/// <param name="totalParam"></param>
/// <returns></returns>
public decimal ApplyDiscount(decimal totalParam)
{
return (totalParam - (1m / 10m * totalParam));
}
}

在价格计算实现类(LinqValueCalculator)内调用打折接口(IDiscountHelper)

    /// <summary>
/// 计算器实现类
/// </summary>
public class LinqValueCalculator : IvalueCalculator
{
/// <summary>
/// 定义一个打折接口
/// </summary>
private IDiscountHelper discount; /// <summary>
/// 用构造函数注入打折类
/// </summary>
/// <param name="discountHelper"></param>
public LinqValueCalculator(IDiscountHelper discountHelper) {
discount = discountHelper;
} /// <summary>
/// 价格计算实现方法
/// </summary>
/// <param name="products"></param>
/// <returns></returns>
public decimal ValueProducts(params Product[] products)
{
//调用打折接口的实现类 来计算价格
return discount.ApplyDiscount(products.Sum(u => u.Price));
} }

那么当我们在调用价格计算类(LinqValueCalculator)时,Ninject会自动帮我们注入打折实现类(DefaultDiscountHelper)

(注:前提是,打折接口(IDiscountHelper)你在之前已经用Ninject绑定了它的实现类打折实现类(DefaultDiscountHelper))

 //Ninject
IKernel ninjectKernel = new StandardKernel();
//把一个接口(IValueCalculator)绑定到一个实现该接口的类(LinqValueCalculator)
ninjectKernel.Bind<IvalueCalculator>().To<LinqValueCalculator>(); //给折扣接口绑定一个默认的打折类
ninjectKernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>(); //向NiNject索要一个IvalueCalculator的实现类
IvalueCalculator calcImpl = ninjectKernel.Get<IvalueCalculator>(); //注意:价格计算类(LinqValueCalculator)类里面有一个折扣接口(IDiscountHelper),折扣接口需要一个具体的折扣类(DefaultDiscountHelper),
//我这里在向 ninjectKernel.Get<IvalueCalculator>() 请求价格计算类(LinqValueCalculator类里面有一个折扣接口)的时候并没有传入折扣实现类
//是ninject自己帮我完成了.
//原理就是在上面我们给打折接口(IDiscountHelper)绑定了一个默认的打折实现类(DefaultDiscountHelper),ninject检测到我们绑定了默认打折实现类(DefaultDiscountHelper),所以自动邦我们补全了; //注入购物车类
ShoppingCart shopping = new ShoppingCart(calcImpl); Console.WriteLine("价格:{0}", shopping.CalculateStockValue());
Console.ReadLine();

知识点2:现在我们的打折实现类(DefaultDiscountHelper)内的折扣力度是写死的,如果我们想让折扣力度由外部传入该肿么办呢?

    /// <summary>
/// 默认折扣计算接口
/// </summary>
public class DefaultDiscountHelper : IDiscountHelper
{
/// <summary>
/// 默认折扣类的打折力度
/// </summary>
public decimal DiscountSize { get; set; } /// <summary>
/// 折扣结算方法
/// </summary>
/// <param name="totalParam"></param>
/// <returns></returns>
public decimal ApplyDiscount(decimal totalParam)
{
return (totalParam - (DiscountSize / 10m * totalParam));
}
}

在NinJect注入具体实现类时,我们可以通过下面的形式对打折力度进去传入

  Ninject核心对象.Bind<绑定的接口>().To<要绑定的实现类>().WithPropertyValue("实现类内部属性的名称",实现类内部属性的值);
        //Ninject
IKernel ninjectKernel = new StandardKernel();
//把一个接口(IValueCalculator)绑定到一个实现该接口的类(LinqValueCalculator)
ninjectKernel.Bind<IvalueCalculator>().To<LinqValueCalculator>(); //给折扣接口绑定一个默认的打折类
ninjectKernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>().WithPropertyValue("DiscountSize", 5M); //向NiNject索要一个IvalueCalculator的实现类
IvalueCalculator calcImpl = ninjectKernel.Get<IvalueCalculator>(); .......

如果要给多个属性赋值,则可以在Bind和To方式后添加多个WithPropertyValue(<属性名>,<属性值>)方法。

同样的我们也可以以形参的形式传入

    /// <summary>
/// 默认折扣计算接口
/// </summary>
public class DefaultDiscountHelper : IDiscountHelper
{
public DefaultDiscountHelper(decimal discountSize)
{
DiscountSize = discountSize;
} /// <summary>
/// 默认折扣类的打折力度
/// </summary>
public decimal DiscountSize { get; set; } /// <summary>
/// 折扣结算方法
/// </summary>
/// <param name="totalParam"></param>
/// <returns></returns>
public decimal ApplyDiscount(decimal totalParam)
{
return (totalParam - (DiscountSize / 10m * totalParam));
}
}

此时在注入实现类时改为

  Ninject核心对象.Bind<绑定的接口>().To<要绑定的实现类>().WithConstructorArgument("形参的名称",形参的值);

调用方法改为

  //把一个接口(IValueCalculator)绑定到一个实现该接口的类(LinqValueCalculator)
ninjectKernel.Bind<IvalueCalculator>().To<LinqValueCalculator>(); //给折扣接口绑定一个默认的打折类
ninjectKernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>().WithConstructorArgument("discountSize",10M); //向NiNject索要一个IvalueCalculator的实现类
IvalueCalculator calcImpl = ninjectKernel.Get<IvalueCalculator>();

如果构造函数存在多个形参那么在每一个后面在.WithConstructorArgument 即可

例如:

  Ninject核心对象.Bind<绑定的接口>().To<要绑定的实现类>().WithConstructorArgument("形参的名称",形参的值).WithConstructorArgument("形参的名称1",形参的值1).WithConstructorArgument("形参的名称2",形参的值2);

知识点3:在对接口进行绑定时我们都是通过如下方法绑定

  //向NiNject索要一个IvalueCalculator的实现类
IvalueCalculator calcImpl = ninjectKernel.Get<IvalueCalculator>(); //把要到的实现类注入到购物车类内部
ShoppingCart shopping = new ShoppingCart(calcImpl);

转换为中文意为:

由计算(IvalueCalculator) 接口 calcImpl  向  ninjectKernel 索要一个(计算接口)IvalueCalculator的具体实现类(LinqValueCalculator)(具体实现类由上面接口绑定而得)的引用;

创建一个(购物车类)ShoppingCart shopping ,指向(购物车)ShoppingCart类并且由构造函数注入前面从ninjectKernel获得的计算接口(IvalueCalculator)的实现类(LinqValueCalculator);

这样写我个人觉得最通俗易懂,但是不够简洁,Ninject还有另外一种更简单的获取实现类的方法

            ninjectKernel.Bind<IvalueCalculator>().To<LinqValueCalculator>();
//给折扣接口绑定一个默认的打折类
ninjectKernel.Bind<IDiscountHelper>().To<DefaultDiscountHelper>().WithConstructorArgument("discountSize",5M);//标识自我绑定
ninjectKernel.Bind<ShoppingCart>().ToSelf();
//注入购物车类
ShoppingCart shopping = ninjectKernel.Get<ShoppingCart>();

由知识点1可知: Ninject 不仅可以 以  接口 绑定 实现类 的 形式 进行 绑定,也可以进行具体类绑定具体类的操作;

这是自我绑定方法,再由上方知识点可推断  当我们要调用的类需要一个接口的实现类时,如果这个接口是在之前已经进行绑定过的,那么Ninject会自动邦我们进行注入

也就是说:

购物车(ShoppingCart)类先进行绑定,它绑定的实现类就是他自己,所有通过Ninject请求购物车(ShoppingCart)类的请求都会返回一个购物车(ShoppingCart)类自己,再因为 已经在Ninject绑定的接口在被调用时都会自动邦我们进行注入操作

(购物车类内部有一个计算接口(IvalueCalculator)计算接口需要一个计算实现类(LinqValueCalculator)  而计算接口在之前我们已经进行了绑定,所以Ninject会自动帮我们进行注入)

最核心的就是要明白,Ninject会对所有已经绑定过的接口进行自动注入实现类的操作.(貌似有一定的递归逻辑?)

这样整个自绑定逻辑就已经缕清楚了~

由"Liam Wang"编写的"[ASP.NET MVC 小牛之路]04 - 依赖注入(DI)和Ninject"整理而成

URL:https://www.cnblogs.com/willick/p/3223042.html

使用Ninject的一般步骤的更多相关文章

  1. [ASP.NET MVC 小牛之路]04 - 依赖注入(DI)和Ninject

    本人博客已转移至:http://www.exblr.com/liam  为什么需要依赖注入 在[ASP.NET MVC 小牛之路]系列的理解MVC模式文章中,我们提到MVC的一个重要特征是关注点分离( ...

  2. [ASP.NET MVC 小牛之路]05 - 使用 Ninject

    在[ASP.NET MVC 小牛之路]系列上一篇文章(依赖注入(DI)和Ninject)的末尾提到了在ASP.NET MVC中使用Ninject要做的两件事情,续这篇文章之后,本文将用一个实际的示例来 ...

  3. C#Console程序使用Ninject

    本来想使用一下Ninject的,然后搜索了很久,都没找到比较详细的关于Ninject的使用方法等内容.于是乎干脆自己来写几篇介绍Ninject的内容. 1.      依赖注入和IOC 依赖注入和IO ...

  4. ASP.NET MVC中使用Ninject

    ASP.NET MVC中使用Ninject 在[ASP.NET MVC 小牛之路]系列上一篇文章(依赖注入(DI)和Ninject)的末尾提到了在ASP.NET MVC中使用Ninject要做的两件事 ...

  5. 依赖注入(DI)和Ninject

    [ASP.NET MVC 小牛之路]04 - 依赖注入(DI)和Ninject 本文目录: 1.为什么需要依赖注入 2.什么是依赖注入 3.使用NuGet安装库 4.使用Ninject的一般步骤 5. ...

  6. [1] Ninject

    为什么使用这种依赖注入的框架呢?我借鉴两张图做一下说明 传统的接口方式,即 IValueCalculator I=new LinqValueCalculator,虽然用接口做的隔离,但是在调用的时候实 ...

  7. 依赖注入框架Ninject

    为什么需要依赖注入 我们提到MVC的一个重要特征是关注点分离(separation of concerns).我们希望应用程序的各部分组件尽可能多的相互独立.尽可能少的相互依赖. 我们的理想情况是:一 ...

  8. 使用 Ninject

    在[ASP.NET MVC 小牛之路]系列上一篇文章(依赖注入(DI)和Ninject)的末尾提到了在ASP.NET MVC中使用Ninject要做的两件事情,续这篇文章之后,本文将用一个实际的示例来 ...

  9. [ASP.NET MVC 小牛之路]05 - 使用 Ninject实现依赖注入

    在[ASP.NET MVC 小牛之路]系列上一篇文章(依赖注入(DI)和Ninject)的末尾提到了在ASP.NET MVC中使用Ninject要做的两件事情,续这篇文章之后,本文将用一个实际的示例来 ...

随机推荐

  1. 【踩坑】iconfont使用异常bug

    你见过html页面上'x'字符变成打印机图标么?一般人应该没有. -----------------------诡异bug----------------------- 今天测试报了一个bug,说页面 ...

  2. 升讯威微信营销系统开发实践:(4)源代码结构说明 与 安装部署说明( 完整开源于 Github)

    GitHub:https://github.com/iccb1013/Sheng.WeixinConstruction因为个人精力时间有限,不会再对现有代码进行更新维护,不过微信接口比较稳定,经测试至 ...

  3. 使用crypto-js对数据进行AES加密、解密

    前段时间做项目有用到数据加密,前端加密,后端解密(前端也可以解密),话不多说进入正题: 第一步: npm i crypto-js -S 第二步: 在需要加密或解密的地方引入crypto-js: imp ...

  4. linux下c编程 基础

    1. 熟悉Linux系统下的开发环境 2. 熟悉vi的基本操作 3. 熟悉gcc编译器的基本原理 4. 熟练使用gcc编译器的常用选项 5 .熟练使用gdb调试技术 6. 熟悉makefile基本原理 ...

  5. Jvm虚拟机结构与机制

    JVM(Java Virtual Machine)在研究JVM的过程中会发现,其实JVM本身就是一个计算机体系结构,很多原理和我们平时的硬件.微机原理.操作系统都有十分相似的地方,所以学习JVM本身也 ...

  6. Mybatis中几个重要类

    http://www.open-open.com/lib/view/open1363572227609.html

  7. Xor Sum 01字典树 hdu4825

    Xor Sum Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 132768/132768 K (Java/Others)Total S ...

  8. 部署项目到tomcat步骤参考如下 2017.7.10

    http://jingyan.baidu.com/article/a501d80c0c65baec630f5ef6.html

  9. 五个最佳RSS新闻阅读器

    文章出自http://www.williamlong.info/archives/1591.html 在博客和在线新闻充斥的互联网上,大量信息已经使得用户阅读量过载,幸运的是,通过RSS Feed提供 ...

  10. Java 读书笔记 (十六) Java 继承

    例: 开发动物类,其中动物分别为企鹅以及老鼠,要求如下: 企鹅: 属性(姓名,id), 方法(吃,睡,自我介绍) 老鼠: 属性(姓名,id), 方法(吃,睡,自我介绍) 企鹅类: public cla ...