IoC模式(控制反转)(转)
转自:http://www.cnblogs.com/qqlin/archive/2012/10/09/2707075.html,写的很好,用C#代码解释控制反转,然后更进一步,提到依赖注入是控制反转的具体实现。其实原理和java的一模一样。
IoC模式
1.依赖
依赖就是有联系,有地方使用到它就是有依赖它,一个系统不可能完全避免依赖。如果你的一个类或者模块在项目中没有用到它,恭喜你,可以从项目中剔除它或者排除它了,因为没有一个地方会依赖它。下面看一个简单的示例:

/// <summary>
/// 用户播放媒体文件
/// </summary>
public class OperationMain
{ public void PlayMedia()
{
MediaFile _mtype = new MediaFile();
Player _player = new Player(); _player.Play(_mtype);
}
}
/// <summary>
/// 播放器
/// </summary>
public class Player
{
public void Play(MediaFile file)
{
Console.WriteLine(file.FilePath);
}
}
/// <summary>
/// 媒体文件
/// </summary>
public class MediaFile
{
public string FilePath { get; set; }
}

上面是一个用户用播放器播放文件简单示例,用户操作是OperationMain类中的PlayMedia方法,打开一个播放器,选择一个文件来播放。先看看他们之间的依赖关系,可以简单找到有3个依赖
- Player依赖MediaFile
- OperationMain依赖Player
- OperationMain依赖MediaFile
2.依赖倒置
需求增加了,要用不同的播放器,播放不同的文件,我们要抽象出来,减少耦合。
耦合关系就是依赖关系,如果依赖关系相当繁杂,牵一发而动全身,很难维护;依赖关系越少,耦合关系就越低,系统就越稳定,所以我们要减少依赖。
幸亏Robert Martin大师提出了面向对象设计原则----依赖倒置原则:
- A. 上层模块不应该依赖于下层模块,它们共同依赖于一个抽象。
- B. 抽象不能依赖于具象,具象依赖于抽象。
理解:A.上层是使用者,下层是被使用者,这就导致的结果是上层依赖下层了,下层变动了,自然就会影响到上层了,导致系统不稳定,甚至是牵一发而动全身。那怎么减少依赖呢?就是上层和下层都去依赖另一个抽象,这个抽象比较稳定,整个就来说就比较稳定了。
B.面向对象编程时面向抽象或者面向借口编程,抽象一般比较稳定,实现抽象的具体肯定是要依赖抽象的,抽象不应该去依赖别的具体,应该依赖抽象。
上面播放器的示例中,我们已经找到依赖关系了,现在我们要按照依赖倒置原则,来进行优化。
根据原则如下改动:
- Player依赖MediaFile,好办,让Player和MediaFile都去依赖一个抽象IMediaFile
- OperationMain依赖Player,好办,让OperationMain和Player都依赖一个抽象IPlayer
- OperationMain依赖MediaFile,好办,让OperationMain和MediaFile都依赖一个抽象IMediaFile
- IPlayer不能依赖具体MediaFile,应该依赖于具体MediaFile的抽象IMediaFile
结构很简单,于是代码大致如下:

/// <summary>
/// 用户播放媒体文件
/// </summary>
public class OperationMain
{ public void PlayMedia()
{
IMediaFile _mtype = new MediaFile();
IPlayer _player = new Player(); _player.Play(_mtype);
}
}
/// <summary>
/// 播放器
/// </summary>
public interface IPlayer
{
void Play(IMediaFile file);
}
/// <summary>
/// 默认播放器
/// </summary>
public class Player : IPlayer
{
public void Play(IMediaFile file)
{
Console.WriteLine(file.FilePath);
}
}
/// <summary>
/// 媒体文件
/// </summary>
public interface IMediaFile
{
string FilePath { get; set; }
}
/// <summary>
/// 默认媒体文件
/// </summary>
public class MediaFile : IMediaFile
{
public string FilePath { get; set; }
}

上面代码进行了抽象,可以看到,目的是减少了依赖,但是看上去依赖关系增加了,如用户PlayMedia方法,依赖还增加了依赖接口和具体的实现,但是接口是稳定的,可以不考虑,具体的实现才是变动的,这个依赖还是要的,要播放文件,必定要用到具体的播放器和具体文件。
3.控制反转(IoC)
现实生活中,是具体的播放器和具体的媒体文件没有关系,你给它一个Mp3文件他可以播放,给它一个Mp4文件它也可以播放,你删掉你的媒体文件,播放器照样在,具体什么播放器,播放什么文件,控制权全部是我们用户自己。
上面的示例中基本实现了隔离,具体的播放器跟具体的媒体隔离了,具体的播放器只跟媒体接口和播放器接口有关。但是PlayMedia的方法里面的具体对象,写死了,控制权非常小,如果我想用百度影音播放呢,我想换一首音乐呢,只能重新改代码,那控制怎么进行转移呢?
我们可以通过反射来创建,把具体的文件名写在配置文件里,这时候客户端代码也不用变了,只需要改配置文件就好了,稳定性又有了提高,如下:

public void PlayMedia()
{
IMediaFile _mtype = Assembly.Load(ConfigurationManager.AppSettings["AssemName"]).CreateInstance(ConfigurationManager.AppSettings["MediaName"]);
IPlayer _player = Assembly.Load(ConfigurationManager.AppSettings["AssemName"]).CreateInstance(ConfigurationManager.AppSettings["PlayerName"]); _player.Play(_mtype);
}

这个具对象是哪一个,全由配置文件来控制了,这个具体对象的控制权交给了配置文件了,这也是人们常说的控制反转。
控制反转IoC是Inversion of Control的缩写,是说对象的控制权进行转移,转移到第三方,比如转移交给了IoC容器,它就是一个创建工厂,你要什么对象,它就给你什么对象,有了IoC容器,依赖关系就变了,原先的依赖关系就没了,它们都依赖IoC容器了,通过IoC容器来建立它们之间的关系。
4.依赖注入(DI)
上面说到控制反转,是一个思想概念,但是也要具体实现的,上面的配置文件也是一种实现方式。依赖注入提出了具体的思想。
依赖注入DI是Dependency Injection缩写,它提出了“哪些东东的控制权被反转了,被转移了?”,它也给出了答案:“依赖对象的创建获得被反转”。
所谓依赖注入,就是由IoC容器在运行期间,动态地将某种依赖关系注入到对象之中。
上面的示例中,哪些要依赖注入,依赖对象需要获得实例的地方,即 PlayMedia方法,需要IPlayer具体对象和IMediaFile的具体对象,找到了地方就从这里下手,为了灵活的控制这两个对象,必须是外面能够控制着两个对象的实例化,提供对外的操作是必要的,可以是属性,可以是方法,可以是构造函数,总之别的地方可以控制它,下面将会使用Unity来注入,使用的是构造函数注入,代码如下:

/// <summary>
/// 用户播放媒体文件
/// </summary>
public class OperationMain
{
IMediaFile _mtype;
IPlayer _player; public OperationMain(IPlayer player, IMediaFile mtype)
{
_player = player;
_mtype = mtype;
} public void PlayMedia()
{
_player.Play(_mtype);
}
}
/// <summary>
/// 播放器
/// </summary>
public interface IPlayer
{
void Play(IMediaFile file);
}
/// <summary>
/// 默认播放器
/// </summary>
public class Player : IPlayer
{
public void Play(IMediaFile file)
{
Console.WriteLine(file.FilePath);
}
}
/// <summary>
/// 媒体文件
/// </summary>
public interface IMediaFile
{
string FilePath { get; set; }
}
/// <summary>
/// 默认媒体文件
/// </summary>
public class MediaFile : IMediaFile
{
public string FilePath { get; set; }
}

给 OperationMain类一个构造函数,因为Unity有一个构造函数注入,调用代码如下:

static UnityContainer container = new UnityContainer();
static void init()
{
container.RegisterType<IPlayer, Player>();
container.RegisterType<IMediaFile, MediaFile>();
}
static void Main(string[] args)
{ init(); OperationMain op1 = container.Resolve<OperationMain>();
op1.PlayMedia();
OperationMain op3 = container.Resolve<OperationMain>();
op3.PlayMedia(); //普通方式
OperationMain op2 = new OperationMain(new Player(), new MediaFile());
op2.PlayMedia(); Console.Read();
}

看出来吧,Unity的功能远不止这些,你可以初始化时注册N多,以后直接使用,而不用使用new,还有实例周期的控制、配置文件等灵活控制,具体可以看看Unity(具体不是本节的范畴)的说明。
5.小结
通过一个小例子由浅入深地进行优化,已加深对IoC模式的理解,我想复杂的结构也是从这种简单的架构累加起来的。
最近在看相关文章,很多都太专业化了没怎么看懂,这是自己现在对IoC的一些理解,记录下来,要不然时间一久,也就忘了。
自己对IoC模式理解还很浅,希望得到各位的指点。
IoC模式(控制反转)(转)的更多相关文章
- 通过laravel理解IoC(控制反转)容器和DI(依赖注入)
原文地址: http://www.insp.top/learn-laravel-container ,转载务必保留来源,谢谢了! 容器,字面上理解就是装东西的东西.常见的变量.对象属性等都可以算是容器 ...
- Spring——IOC(控制反转)与DI(依赖注入)
IOC与DI的理解及使用 控制反转IOC(Inversion of Control)是一种设计思想,DI(依赖注入)是实现IOC的一种方法.在没有IOC的程序中,我们使用面向对象编程,对象的创建于对象 ...
- spring 概念之:IoC(控制反转)
IoC(控制反转,Inverse of Control) IoC 的字面意思是控制反转,它包括两方面的内容: 控制 反转 那到底是什么东西的"控制"被"反转"了 ...
- 谈谈对Spring IOC(控制反转)的理解--转
谈谈对Spring IOC(控制反转)的理解--转 学习过Spring框架的人一定都会听过Spring的IoC(控制反转) .DI(依赖注入)这两个概念,对于初学Spring的人来说,总觉得IoC ...
- IOC(控制反转)的理解
1.IOC的理论背景 我们知道在面向对象设计的软件系统中,它的底层都是由N个对象构成的,各个对象之间通过相互合作,最终实现系统地业务逻辑[1]. 图1 软件系统中耦合的对象 如果我们打开机械式手表的后 ...
- IOC/DI控制反转与依赖注入
IOC/DI控制反转与依赖注入 IOC和DI表现的效果的是一样的只不过对于作用的对象不同,有了不一样的名字. 先用一个现实的例子来说明IOC/DI表现出来的效果.
- IOC(控制反转)和DI(依赖注入)
IOC(控制反转): 那么IoC是如何做的呢?有点像通过婚介找女朋友,在我和女朋友之间引入了一个第三者:婚姻介绍所.婚介管理了很多男男女女的资料,我可以向婚介提出一个列表,告诉它我想找个什么样的女朋友 ...
- 工厂方法模式与IoC/DI控制反转和依赖注入
IoC——Inversion of Control 控制反转 DI——Dependency Injection 依赖注入 要想理解上面两个概念,就必须搞清楚如下的问题: 参与者都有谁? 依赖:谁 ...
- .NET IoC模式依赖反转(DIP)、控制反转(Ioc)、依赖注入(DI)
依赖倒置原则(DIP) 依赖倒置(Dependency Inversion Principle,缩写DIP)是面向对象六大基本原则之一.他是指一种特定的的解耦形式,使得高层次的模块不依赖低层次的模块的 ...
随机推荐
- Delphi调试CGI或ISAPI 转
因为dll文件已驻留内存,可用intrabob进行调试,也可用PWS进行调试,不过要换文件. IntraBob是资深程序员Dr.Bob编写的免费工具软件,用于测试Delphi编写 的CGI/Win ...
- UIImageVIew的使用
UIImageView是一个用于显示图片的控件 构造方法: UIImage * tempImage = [UIImage imageNamed:IMAGE_NAME]; imageVi ...
- asterisk帮助与国内论坛
http://www.in2eps.com/fo-abnf/tk-fo-abnf-http.html www.asteriskguru.com/ http://www.voip-info.org/ h ...
- ng-select ng-options ng-repeat的用法与区别
最近在用angularJS里的ng-select,ng-options,ng-repeat,发现有两点不太方便: 1.当数据复杂时,循环起来比较麻烦 2.首选项如果不设置,就会为空 整理一下它们的用法 ...
- linux 设置 jdk环境变量
1.安装jdk tar zxvf jdk-8u112-linux-i586.tar.gz 2.设置环境变量:vi /etc/profile 输入i加入内容如下:export JAVA_HOME=/u ...
- 自己动手画一个HTML5的按钮
<!DOCTYPE HTML> <html lang="en-US"> <head> <meta charset="UTF-8& ...
- winform 加密 解密 分类: WinForm 2014-05-16 15:05 400人阅读 评论(0) 收藏
界面显示: 加密: 解密: 代码实现: public string EncryptString(string str) { #region 加密程序 ...
- 异常Address already in use: JVM_Bind的处理
如题,Address already in use: JVM_Bind这个异常的意思就是说jvm被占用了 那么大家一般的解决情况都是重启一下eclipse , 结果还是不行,结果就只能重启电脑了. 对 ...
- UltraISO对光盘镜像的常用操作
UltraISO,它能直接编辑光盘映像或者从光盘映像文件里面提取文件:可以从CD-ROM里面制作光盘映像:也可以把硬盘上的文件制作成ISO文件:可以把ISO中启动信息保存下来,也可以为ISO添加启动功 ...
- [转] webpack debug in webstorm
先run build,然后用node server.js来做 WebStorm 11 adds support for debugging client-side apps built with We ...