话说写代码已有数年,曾经花了很多时间,看了很多大牛的文章也是不能参透,日思夜想都没有理解的概念,通过不断的实践与学习,回过头来再看,总算有了一个清晰的理解与认识,也看到一句话说,最好的学习就是把别人教会,因此想把这些曾经我很难理解的知识以我认为最易理解的形式分享出来。

之所以把委托和IOC放在一起,是因为下文这一个场景可以解释这两个概念。

1)委托

这里只谈委托的使用场景,不谈那些令人烦恼的概念。

比如,你所参与的项目需要一个功能,需要实现在互联网上下载音频文件。这个时候,你要写一个下载类,下载完成后,还要实现播放、备份这两个操作。这个下载类是只有下载一个功能,至于播放和备份,是另外两个类需要做的事。

这种场景,用委托是最合适的了,也很利于以后的扩展,下载完成后,还可能有播放提示音、关机等等的操作。

至于.net里面的事件,也是这样用的,这里下载完成就相当于一个事件,很多框架里也是这样用的。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading; namespace ConsoleApplication1
{
public delegate void DownloadFinish(string file);
class DownLoader
{
public DownloadFinish DownloadFinishHandler; public void Download()
{
Console.WriteLine("开始下载...");
Thread.Sleep();
Console.WriteLine("下载完成");
string downloadedfile = @"c:\fly.mp3";
if (DownloadFinishHandler != null)
{
DownloadFinishHandler(downloadedfile);
}
}
}
}

下载类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading; namespace ConsoleApplication1
{
class MusicPlayer
{
public void Play(string file)
{
Console.WriteLine("开始播放文件 " + file);
Thread.Sleep();
Console.WriteLine("播放文件完成");
}
}
}

音乐播放类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading; namespace ConsoleApplication1
{
class FileBak
{
public void Back(string file)
{
Console.WriteLine("开始备份文件"+file);
Thread.Sleep();
Console.WriteLine("备份文件完成");
}
}
}

文件备份类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
//委托演示
var downloader = new DownLoader();
downloader.DownloadFinishHandler += new FileBak().Back;
downloader.DownloadFinishHandler += new MusicPlayer().Play;
downloader.Download();
Console.Read();
}
}
}

调用类

2)IOC(依赖注入)

这里设定的场景是,下载音乐,然后播放。

先看一下没有IOC时的写法。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading; namespace ConsoleApplication2
{
class DownLoader
{
public void Download()
{
Console.WriteLine("开始下载...");
Thread.Sleep();
Console.WriteLine("下载完成");
string downloadedfile = @"c:\fly.mp3"; var player = new MusicPlayer();
player.Play(downloadedfile);
}
}
}

下载类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading; namespace ConsoleApplication2
{
class MusicPlayer
{
public void Play(string file)
{
Console.WriteLine("开始播放文件 " + file);
Thread.Sleep();
Console.WriteLine("播放文件完成");
}
}
}

音乐播放类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace ConsoleApplication2
{
class Program
{
static void Main(string[] args)
{
//无IOC演示
var downloader = new DownLoader();
downloader.Download();
Console.Read();
}
}
}

调用类

可以看到下载类和音乐播放类耦合了。

再看用构造函数注入后,也就是使用IOC后的写法。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading; namespace ConsoleApplication3
{
class DownLoader
{
private IMusicPlayer musicPlayer; public DownLoader()
{ } public DownLoader(IMusicPlayer player)
{
musicPlayer = player;
} public void Download()
{
Console.WriteLine("开始下载...");
Thread.Sleep();
Console.WriteLine("下载完成");
string downloadedfile = @"c:\fly.mp3"; if (musicPlayer != null)
{
musicPlayer.Play(downloadedfile);
}
}
}
}

下载类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace ConsoleApplication3
{
interface IMusicPlayer
{
void Play(string file);
}
}

音乐播放类接口

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading; namespace ConsoleApplication3
{
class MusicPlayer : IMusicPlayer
{
public void Play(string file)
{
Console.WriteLine("开始播放文件 " + file);
Thread.Sleep();
Console.WriteLine("播放文件完成");
}
}
}

音乐播放类

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
//IOC演示
var player = new MusicPlayer();
var downloader = new DownLoader(player);
downloader.Download();
Console.Read();
}
}
}

调用类

这个时候,多了个一个接口,下载类在编译时依赖这个接口,实例化时,再把具体的类传给它。
2004年,Martin Fowler探讨了同一个问题,既然IOC是控制反转,那么到底是“哪些方面的控制被反转了呢?”,经过详细地分析和论证后,他得出了答案:“获得依赖对象的过程被反转了”。控制被反转之后,获得依赖对象的过程由自身管理变为了由IOC容器主动注入。于是,他给“控制反转”取了一个更合适的名字叫做“依赖注入(Dependency Injection)”。他的这个答案,实际上给出了实现IOC的方法:注入。所谓依赖注入,就是由IOC容器在运行期间,动态地将某种依赖关系注入到对象之中。

所以,依赖注入(DI)和控制反转(IOC)是从不同的角度的描述的同一件事情,就是指通过引入IOC容器,利用依赖关系注入的方式,实现对象之间的解耦。

文章源代码下载

委托、IOC全知道的更多相关文章

  1. 【死磕 Spring】----- IOC 之深入理解 Spring IoC

    在一开始学习 Spring 的时候,我们就接触 IoC 了,作为 Spring 第一个最核心的概念,我们在解读它源码之前一定需要对其有深入的认识,本篇为[死磕 Spring]系列博客的第一篇博文,主要 ...

  2. IOC 之深入理解 Spring IoC

    在一开始学习 Spring 的时候,我们就接触 IoC 了,作为 Spring 第一个最核心的概念,我们在解读它源码之前一定需要对其有深入的认识,本篇为[死磕 Spring]系列博客的第一篇博文,主要 ...

  3. C#语法之委托和事件

    从大学就开始做C#这块,也做C#几年了,最近又从ios转回.Net,继续做C#,之前也没有写博客的习惯,写博客也是从我做ios的时候开始的,现在既然又做回了.net,那就写点关于.Net的博客,可能在 ...

  4. IOC DI 专题

    IoC:Inversion of Control,控制反转DI:Dependency Injection,依赖注入 要理解上面两个概念,就必须搞清楚如下的问题: 参与者都有谁?依赖:谁依赖于谁?为什么 ...

  5. 实现一个自己的IOC

    实现一个自己的IOC package com.IocExample; import java.lang.reflect.Constructor; import java.lang.reflect.In ...

  6. Spring4学习回顾之路02—IOC&DI

    IOC&DI介绍 ●IOC:(Inversion of Control) :控制反转(反向获取资源) 其思想是反转资源获取的方向.传统的资源上查找方式要求组件向容器发起请求查找资源,作为回应, ...

  7. 【SpringBoot】 理解Spirng中的IOC原理

    前言 前文已经介绍了Spring Bean的生命周期,在这个周期内有一个重要的概念就是: IOC容器 大家也知道IOC是Sping 的重要核心之一,那么如何理解它呢,它又是产生什么作用呢?本文就IOC ...

  8. Spring IoC(一)bean实例化和依赖注入

    1.IoC容器概述 IoC 全称为 Inversion of Control,翻译为 “控制反转”,它还有一个别名为 DI(Dependency Injection),即依赖注入. 所谓 IOC ,就 ...

  9. Spring入门之一-------实现一个简单的IoC

    一.场景模拟 public interface Human { public void goHome(); } Human:人类,下班了该回家啦 public interface Car { void ...

随机推荐

  1. Shell基础-环境变量配置文件

    Shell基础-环境变量配置文件 source 配置文件 或者 . 配置文件: 把环境变量写入配置文件后,需要用户重新登陆才能生效,而是用source命令,则能直接生效 主要的配置文件: /etc/p ...

  2. C#的循环语句练习

    1.输入一个整数,算出从1到这个数每个数阶乘的和. 2.求100以内质数的和. 3.有一对幼兔,幼兔1个月后长成小兔,小兔1个月后长成成兔并生下一对幼兔,问几个月后有多少对兔子,幼兔,小兔,成兔分别是 ...

  3. Clojure web初探

    项目环境:3.2.0-52-generic #78-Ubuntu SMP Fri Jul 26 16:21:44 UTC 2013 x86_64 x86_64 x86_64 GNU/LinuxLein ...

  4. Java中对数据库的查询和增加内容

    先添加jar包 查询数据库中的信息 加载访问驱动,com.mysql.jdbc.Driver--连接到库--写SQL语句 用while循环把表中的信息从第一条到最后一条打印出来,括号中的数字是代表数据 ...

  5. 使用gnucash查看任意时间段内的所有者权益变动表

    gnucash默认会以当年的会计账期显示所有者权益变动表 如果要看指定时间的所有者权益变动表,需要这样做 打开所有者权益变动表 点击上面的[选项] 如图 在常规中自行选择日期 确定后就能够看到指定时间 ...

  6. python之读取cdv

    csv是Comma-Separated Values的缩写,是用文本文件形式储存的表格数据,比如如下的表格: 就可以存储为csv文件,文件内容是:No.,Name,Age,Score1,Apple,1 ...

  7. 自学 PHP,如何不走弯路?

    1.一本好书至关重要.如果这本书的知识非常深入,那么还是不要看了.对初学者来说只能是打击.因为很多东西都看不懂.一本知识较为浅显,并且说明非常详细,但是能让你上手的基础知识又非常完善的书籍就非常好.( ...

  8. ie7中ul不能嵌套div和li平级

    我要讲一个忧伤的故事,本以为清晰的层次结构,ul里不能嵌套div和li平级,不然会乱乱乱! 代码: <ul class="catshow">              ...

  9. MongoDB学习笔记五:聚合

    『count』count是最简单的聚合工具,返回集合中的文档数量:> db.foo.count()0> db.foo.insert({"x" : 1})> db. ...

  10. php中奖概率算法,可用于刮刮卡,大转盘等抽奖算法

    php中奖概率算法,可用于刮刮卡,大转盘等抽奖算法.用法很简单,代码里有详细注释说明,一看就懂 <?php /* * 经典的概率算法, * $proArr是一个预先设置的数组, * 假设数组为: ...