实现依赖倒置、控制反转、依赖注入的核心思想是:接口驱动

接口驱动有很多好处,可以提供不同灵活的子类实现,增加代码稳定和健壮性,实现模块之间的解耦等等。

参考资料:https://www.cnblogs.com/fuchongjundream/p/3873073.html

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.依赖倒置 (Dependence Inversion Principle)

需求增加了,要用不同的播放器,播放不同的文件,我们要抽象出来,减少耦合。

耦合关系就是依赖关系,如果依赖关系相当繁杂,牵一发而动全身,很难维护;依赖关系越少,耦合关系就越低,系统就越稳定,所以我们要减少依赖。

幸亏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.控制反转(Inverse of Control)

现实生活中,是具体的播放器和具体的媒体文件没有关系,你给它一个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.依赖注入(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(具体不是本节的范畴)的说明。

依赖注入的标志:

  1. 方法的参数为接口

  2. 在外部创建实例,并通过参数传入方法中,最终返回容器实例

  3. 调用容器的统一方法

依赖倒置、控制反转、依赖注入相关推荐

  1. 那些年搞不懂的高深术语——依赖倒置•控制反转•依赖注入•面向接口编程...

    那些年,空气中仿佛还能闻到汉唐盛世的余韵,因此你决不允许自己的脸上有油光,时刻保持活力.然而,你一定曾为这些"高深术语"感到过困扰--依赖倒置•控制反转•依赖注入•面向接口编程.也 ...

  2. 那些年搞不懂的高深术语——依赖倒置•控制反转•依赖注入•面向接口编程【转】...

    那些年,空气中仿佛还能闻到汉唐盛世的余韵,因此你决不允许自己的脸上有油光,时刻保持活力.然而,你一定曾为这些"高深术语"感到过困扰.也许时至今日,你仍对它们一知半解.不过就在今天, ...

  3. 高深术语——依赖倒置•控制反转•依赖注入•面向接口编程

    今天,我将带领你以一种全新的高清视角进入奇妙的编程世界,领略涵泳在这些"高深术语"中的活泼泼的地气,以及翩跹于青萍之末的云水禅心. 高聚合·低耦合 简短:管理好自己(内聚),但是有 ...

  4. 【转】那些年搞不懂的高深术语——依赖倒置•控制反转•依赖注入•面向接口编程

    作者:在好 链接:https://www.zhihu.com/question/31021366/answer/102239756 来源:知乎 著作权归作者所有.商业转载请联系作者获得授权,非商业转载 ...

  5. Software--IoC 依赖倒置 控制反转

    软件开发设计原则 S.O.L.I.D 中的 Idependence Convert 转载于:https://www.cnblogs.com/masterSoul/p/7849519.html

  6. Spring 的控制反转/依赖注入

    第一章 Spring 的控制反转/依赖注入 回顾 增删改查. 课前测: 本章内容 spring:春天 IOC:将创建对象的权力交给 spring 核心容器去控制.工厂模式 BeanFactory: 懒 ...

  7. 控制反转-依赖倒置-依赖注入

    控制反转:框架控制应用/组件 依赖倒置: 依赖注入:框架动态注入依赖关系到应用/组件 --------------------------------------------------------- ...

  8. 控制反转---依赖注入理解

    在学习Spring的时候,意外找到这个控制反转(IoC)和面向切面(AOP)的容器框架之前,我们先来看一下什么是控制反转(IoC). 控制反转(Ioc)和依赖注入(DI)刚听到感到很难理解,平时也程序 ...

  9. 设计模式——控制反转依赖注入

    一.控制反转: 从简单的代码示例入手: /// <summary>/// 邮件服务类/// </summary>public class EmailService{public ...

  10. 【C#|.NET】从控制反转(依赖注入)想到事件注入 (非AOP)

    前文 事件注入的想法是由依赖注入所联想到 依赖注入不算什么吸引人的话题 本篇就不详说了 不过有闲暇时间的机会不妨按照自己的兴趣去摸索.研究一些东西,也是一种乐子. 在抓虫系列里简单的描述一下依赖注入在 ...

最新文章

  1. 约瑟夫环问题的两种解法(详解)
  2. win10 便签无法联网_便签 | win10无法搜索到wifi的解决方案
  3. linux命令全集,Linux命令全集
  4. Android性能调优利器StrictMode
  5. 主页面功能的java_6-04-项目实战-主页面显示当前用户退出功能实现
  6. 测试m.2固态的软件,Ryzen新平台下M.2固态硬盘性能测试
  7. 线程的同步与互斥,死锁
  8. 南阳理工acm 1070诡异的电梯【Ⅰ】(动态规划)
  9. Apple Pay接入详细教程
  10. 剪映怎么导入mkv_mkv用什么播放器打开_什么播放器可以打开mkv格式-系统城
  11. java实现发送短信和邮箱
  12. websocket握手失败_WebSocket握手总结
  13. 【工具】kindle 怎么用微信读书
  14. 克隆Linux虚拟机
  15. 软件测试需要会python吗_真实揭秘90后职业新选择:25岁刚入行软件测试,竟拿到这么多薪资……...
  16. php 删除文件 unlink,php 删除文件函数unlink及删除文件夹示例
  17. 高人总结,告诉你输入输出阻抗是怎么回事?
  18. mysql分片做主从_使用mycat部署mysql集群(分片,读写分离,主从复制)
  19. 如何查看自己的CSDN积分
  20. 【前端王一】 - 前端学习路线

热门文章

  1. 怎样批量解析手机端头条视频和封面图片并保存
  2. 相对于就业来讲,前端工程师和后端开发哪个比较好?
  3. ecshop清空购物车提醒,ecshop购物车,ecshop清空购物车,ecshop提醒信息,ecshop清空操作提示
  4. Netease Music Spider
  5. bwa mem 报错处理:[mem_sam_pe] paired reads have different names
  6. 小学计算机课题研究方案,《小学信息技术课堂有效教学的探究》课题研究方案...
  7. 三步必杀(P4231)
  8. Intellij IDEA中修改Maven项目的项目名称
  9. PFC161台湾应广单片机PFC161S08A/PFC161S08B带硬件触摸功能单片机
  10. k8s.gcr.io的镜像无法下载的问题