我曾想深刻了解的:依赖倒置、控制反转、依赖注入

大道至简

咱们在软件工程中进行的架构设计、模块实现、编码等工做,不少时候说到底就是围绕一件事进行:解耦。编程

三层架构,MVC,微服务,DDD.咱们分析问题,抽象问题,而后划分边界,划分层次。设计模式

也是为了让咱们的类、模块、系统有更强的复用能力,提升生产效率。架构

这一次,我想深刻了解和探讨我曾经很迷糊,也没有一直仔细了解的:依赖倒置、控制反转、依赖注入 这些概念。mvc

什么是依赖?

一般能够理解为一种须要,需求。须要协助才能完成一件事情。

例如,咱们依赖日志服务写日志:框架

public class Contract
    {
       public void Successed()
        {
            string msg = "save, successed!";
            Log log = new Log();
            log.Write(msg);
        }
    }

Contract类正依赖Log类,协助完成整个业务流程。这就产生了依赖。函数

什么是抽象? 什么是细节?

咱们常常会据说,面向接口编程,依赖于抽象不能依赖于具体实现细节。微服务

咱们每次修改接口时候,必定会去修改具体实现。可是咱们修改具体实现却不多修改接口。编码

因此接口比具体实现更稳定。架构设计

此时,咱们在中间加入一层接口,看看如何。设计

public interface ILog
    {
        void Write();
    }
public void Successed()
     {
         string msg = "save, successed!";
         
         ILog log = new Log();
         log.Write(msg );
     }

关系变化如图:

什么是上层模块? 什么是底层模块?

此时,Contract类能够看作上层。Log看作底层。

上层模块:指挥控制

底层模块:策略实现

依赖倒置

理清楚了 上层、底层、细节、抽象、依赖概念,

咱们不难发现,上面的依赖箭头发生了改变。

因此依赖倒置也由此而来:

上层模块不该该依赖底层模块,它们都应该依赖于抽象。
抽象不该该依赖于细节,细节应该依赖于抽象。

依赖倒置,使得咱们的扩展性加强。

public class Log:ILog
public class NLog : ILog
public class Log4 : ILog
// ILog log = new Log();
// ILog log = new Log4();
ILog log = new NLog();
log.Write(msg);

以上代码咱们也能够看出,咱们须要不断注释修改Contract类,以致于引用不一样的Log组件来应对需求。

每次都要修改这个类来知足需求(修改关闭,扩展开放原则),显然是咱们所不但愿的。形成这种现象的缘由是:

由于对于上层的Contract类,不只仅负责业务逻辑的实现,第二职责还要负责日志实例的构造。

对于Program类,有日志服务类直接拿来使用便可,不须要关心这些实例的构造。

有没有一种机制可以将构造和使用进行分离?使得Contract的职责更加单一,耦合更低?(单一职责原则)

控制反转

怎么算是控制反转了呢?

咱们改一下上面的代码将日志类的实例化控制权,转移到类的外部:

public class Contract
    {
      public Contract(ILog log)
    }

调用

class Program
    {
        static void Main(string[] args)
        {
            ILog log = new NLog();
            Contract contract = new Contract(log);
            contract.Successed();
        }
    }

这样,不管外部日志组件如何变化,都不用会影响现有的Contract类。

Contract只专一于属于本身的职责。上层Contract类和日志类解耦更加完全。互不影响。

若是从职责角度来看,咱们是否是能够有一个类专门来管理建立日志类呢?

就像仓库管理员同样,根据单子出货,不须要关心这些货物到底如何被使用的。

public static class Ioc
    {
        public static ILog GetLogInstance(int type)
        {
            switch (type)
            {
                case 1: return new Log();
                case 2: return new Log4();
                case 3: return new NLog();
                default: return new Log();
            }
        }
    }
class Program
    {
        static void Main(string[] args)
        {           
            ILog log = Ioc.GetLogInstance(1);
            Contract contract = new Contract(log);
            contract.Successed();
        }
    }

依赖注入

什么是依赖注入呢?

其实咱们刚刚已经实现过了,全文先是依赖倒置,而后控制反转,而如今说的依赖注入是控制反转的具体实现方式。

依赖注入是解开依赖并实现反转的一种手段。

大约分为三种方式:

  • 构造函数方式
public class Contract
    {
        private ILog _log { get; set; }
        public Contract(ILog log)
        {
            _log = log;
        }
    }

优势: 构造Contract就肯定好依赖。
缺点:后期没法更改依赖。

  • Set方式注入
public class Contract
    {
        private ILog _log { get; set; }
        public Contract(ILog log)
        {
            _log = log;
        }
        public void Successed()
        {
            string msg = "save, successed!";
            _log.Write(msg);
        }

        public void SetLogInstance(ILog log)
        {
            _log = log;
        }
    }

优势: 将Log实例化延迟,Contract类能够灵活变更依赖。
缺点:使用_log前须要判断null状况

  • 接口方式注入
public interface ILogSetter
    {
        ILog Setter(ILog log);
    }
public class Contract: ILogSetter
    {
        ... ...
        public ILog Setter(ILog log)
        {
            _log = log;
            return _log;
        }
    }

接口方式和方式二有点相似,这里将依赖注入提高为一种能力,能够支配依赖关系的能力。

探讨 控制反转

从这个图中,能够看到依赖的倒置,这里低层定义接口并继承实现,高层引用低层定义的接口进行调用使用。

那么如今的控制权是在低层,那么定义接口这个权力到底属于谁?

好比咱们有一个流程对应着5个步骤,这5个步骤又对应着5个接口:A1,A2,A3,A4,A5

业务系统a,须要使用这个流程就须要依次调用这5个接口:A1 -> A2 -> A3 -> A4 -> A5

如今这个流程很是公用,已经上升成为企业级中台的一个流程,愈来愈多的业务系统给都在对接。

此时,不少的业务系统须要从新用代码组织一套这样的调用流程,固然如今的控制权仍是在业务系统这里。

因此此时咱们对外公开的5个接口,只是简单提供了调用能力,对于接口的编排所有寄但愿于业务系统。

这个时候会有两种声音:
一、业务系统不想这么繁琐地重复着编排这些接口
二、中台也想把流程控制权掌握在本身手中,这样遇到业务流程的总体性变动,业务系统是不须要调整的

业务流程引擎的加入,就像是咱们的接口同样,它负责接口的编排,而后成为业务流程。

此时,控制权实际在接口提供方。

模式

咱们想使用微软提供的MVC框架,只要是遵循MVC框架的约定就能拥有MVC的能力。

MVC的控制权在框架,应用想经过框架提供的MVC能力就必须按照框架的定义去作。

若是框架仅仅是给i咱们提供相似于类库同样的MVC实现,

那么整个流程是应用系统本身根据文档,调用各类类库文件,编排这些实现知足业务系统的MVC需求

因此,如今的Asp.Net Core 给咱们提供的MVC,只要是咱们遵循mvc约定,引擎就会推进整个信息的流动,最终反馈给应用。

这种比较普适的流程或者方案,咱们能够成为模式,相似于设计模式,MVC模式.

原来算落在业务系统中的控制权,反向转到模式中。

总结

依赖倒置能够很小也能够很大,

控制反转也能够很小也能够很大。

这种思想咱们无时无刻能够碰到。

相关文章
相关标签/搜索