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

之所以把委托和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. 关于js的keycode13

    一个form 里面只有一个input的时候  触发keydown 之类的事件  表单会在你的动作之外再次提交一次.并且 字段使用的是input的id  而不是name  可以在form上加一个onsu ...

  2. DFS序详解

    dfs序就是一棵树在dfs遍历时组成的节点序列. 它有这样一个特点:一棵子树的dfs序是一个区间. 下面是dfs序的基本代码: void dfs(int x,int pre,int d){//L,R表 ...

  3. C#中String转int问题

    String转int主要有四种方法 1. int.Parse()是一种类容转换:表示将数字内容的字符串转为int类型. 如果字符串为空,则抛出ArgumentNullException异常: 如果字符 ...

  4. js键盘事件全面控制详解

      js键盘事件全面控制 主要分四个部分第一部分:浏览器的按键事件第二部分:兼容浏览器第三部分:代码实现和优化第四部分:总结 第一部分:浏览器的按键事件 用js实现键盘记录,要关注浏览器的三种按键事件 ...

  5. ubuntu 16.04 启用root用户方法

    引用:http://blog.csdn.net/sunxiaoju/article/details/51993091 1.使用:sudo passwd root设置root的密码,如下图所示: 2.使 ...

  6. 远程监控显示brother数控机床数据

    最近几个月公司太忙了,到现在已经连续出差两个多月了. 这个项目这要做mes系统,涉及到产品在机床的加工过程监控,然后led看板显示产品进度. 这里的主角是日本的brother数控机床,服务器按照一定频 ...

  7. 基于 fuzz 技术验证移动端 app 的健壮性

    问题定义 app发布后经常容易出现各种诡异的crash, 这些crash固然可以通过各种崩溃分析服务去定位. 但是的确很影响用户体验. 在crash分类中有一类是后端接口引发的. 比如常见的引发app ...

  8. SQL总结系列

    SQL总结系列 总结SQL基本知识.用法,并结合多年的应用对SQL有关的相关知识进行总结.希望这些分享能给大家带来一些帮助,如有不足或错误,请批评指正. 主要内容 1)编辑相关,包括:数据库的创建与删 ...

  9. MyEclipse、Eclipse复制web项目

    假设现在已经有一个Java Web项目 ProjectA,现在想做另外一个项目ProjectB,它里面绝大部分功能和结构都可以复用ProjectA中的: 我们就可以通过复制项目的方法来做,具体步骤如下 ...

  10. vim中执行shell命令

    1):!command   不退出vim,并执行shell命令command,将命令输出显示在vim的命令区域,不会改变当前编辑的文件的内容   例如   :!ls -l   特别的可以运行:!bas ...