11、理解IoC模式

一、依赖

依赖就是有联系,有地方使用到它就是有依赖它,一个系统不可能完全避免依赖。如果你的一个类或者模块在项目中没有用到它,恭喜你,可以从项目中剔除它或者排除它了,因为没有一个地方会依赖它。下面看一个简单的示例:

///

/// 用户播放媒体文件

///

publicclassOperationMain

{

publicvoidPlayMedia()

{

MediaFile_mtype=newMediaFile();

Player_player=newPlayer();

_player.Play(_mtype);

}

}

///

/// 播放器

///

publicclassPlayer

{

publicvoidPlay(MediaFilefile)

{

Console.WriteLine(file.FilePath);

}

}

///

/// 媒体文件

///

publicclassMediaFile

{

publicstringFilePath{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

结构很简单,于是代码大致如下:

///

/// 用户播放媒体文件

///

publicclassOperationMain

{

publicvoidPlayMedia()

{

IMediaFile_mtype=newMediaFile();

IPlayer_player=newPlayer();

_player.Play(_mtype);

}

}

///

/// 播放器

///

publicinterfaceIPlayer

{

voidPlay(IMediaFilefile);

}

///

/// 默认播放器

///

publicclassPlayer:IPlayer

{

publicvoidPlay(IMediaFilefile)

{

Console.WriteLine(file.FilePath);

}

}

///

/// 媒体文件

///

publicinterfaceIMediaFile

{

stringFilePath{get;set;}

}

///

/// 默认媒体文件

///

publicclassMediaFile:IMediaFile

{

publicstringFilePath{get;set;}

}

上面代码进行了抽象,可以看到,目的是减少了依赖,但是看上去依赖关系增加了,如用户PlayMedia方法,依赖还增加了依赖接口和具体的实现,但是接口是稳定的,可以不考虑,具体的实现才是变动的,这个依赖还是要的,要播放文件,必定要用到具体的播放器和具体文件。

三、控制反转

现实生活中,是具体的播放器和具体的媒体文件没有关系,你给它一个Mp3文件他可以播放,给它一个Mp4文件它也可以播放,你删掉你的媒体文件,播放器照样在,具体什么播放器,播放什么文件,控制权全部是我们用户自己。

上面的示例中基本实现了隔离,具体的播放器跟具体的媒体隔离了,具体的播放器只跟媒体接口和播放器接口有关。但是PlayMedia的方法里面的具体对象,写死了,控制权非常小,如果我想用百度影音播放呢,我想换一首音乐呢,只能重新改代码,那控制怎么进行转移呢?

我们可以通过反射来创建,把具体的文件名写在配置文件里,这时候客户端代码也不用变了,只需要改配置文件就好了,稳定性又有了提高,如下:

publicvoidPlayMedia()

{

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,将对象的创建和获取提取到外部。由外部容器提供需要的组件。

上面的示例中,哪些要依赖注入,依赖对象需要获得实例的地方,即 PlayMedia方法,需要IPlayer具体对象和IMediaFile的具体对象,找到了地方就从这里下手,为了灵活的控制这两个对象,必须是外面能够控制着两个对象的实例化,提供对外的操作是必要的,可以是属性,可以是方法,可以是构造函数,总之别的地方可以控制它,下面将会使用Unity来注入,使用的是构造函数注入,代码如下:

///

/// 用户播放媒体文件

///

publicclassOperationMain

{

IMediaFile_mtype;

IPlayer_player;

publicOperationMain(IPlayerplayer,IMediaFilemtype)

{

_player=player;

_mtype=mtype;

}

publicvoidPlayMedia()

{

_player.Play(_mtype);

}

}

///

/// 播放器

///

publicinterfaceIPlayer

{

voidPlay(IMediaFilefile);

}

///

/// 默认播放器

///

publicclassPlayer:IPlayer

{

publicvoidPlay(IMediaFilefile)

{

Console.WriteLine(file.FilePath);

}

}

///

/// 媒体文件

///

publicinterfaceIMediaFile

{

stringFilePath{get;set;}

}

///

/// 默认媒体文件

///

publicclassMediaFile:IMediaFile

{

publicstringFilePath{get;set;}

}

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

staticUnityContainercontainer=newUnityContainer();

staticvoidinit()

{

container.RegisterType();

container.RegisterType();

}

staticvoidMain(string[]args)

{

init();

OperationMainop1=container.Resolve();

op1.PlayMedia();

OperationMainop3=container.Resolve();

op3.PlayMedia();

//普通方式

OperationMainop2=newOperationMain(newPlayer(),newMediaFile());

op2.PlayMedia();

Console.Read();

}

看出来吧,Unity的功能远不止这些,你可以初始化时注册N多,以后直接使用,而不用使用new,还有实例周期的控制、配置文件等灵活控制,具体可以看看Unity(具体不是本节的范畴)的说明。

具体依赖注入划分为三种形式,即构造器注入、属性(设置)注入和接口注入,习惯将其划分为一种(类型)匹配和三种注入:

类型匹配(Type Matching):虽然我们通过接口(或者抽象类)来进行服务调用,但是服务本身还是实现在

某个具体的服务类型中,这就需要某个类型注册机制来解决服务接口和服务类型之间的匹配关系;

构造器注入(Constructor Injection):IoC容器会智能地选择选择和调用适合的构造函数以创建依赖的对象。如果被选择的构造函数具有相应的参数,IoC容器在调用构造函数之前解析注册的依赖关系并自行获得相应参数对象;

属性注入(Property Injection):如果需要使用到被依赖对象的某个属性,在被依赖对象被创建之后,IoC容器会自动初始化该属性;

方法注入(Method Injection):如果被依赖对象需要调用某个方法进行相应的初始化,在该对象创建之后,IoC容器会自动调用该方法。

用配置完成注册

具体实现代码:

UnityConfigurationSectionconfiguration=ConfigurationManager.GetSection(UnityConfigurationSection.SectionName)

asUnityConfigurationSection;

configuration.Configure(container,"defaultContainer");

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容