热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

开发笔记:我曾想深入了解的:依赖倒置控制反转依赖注入

大道至简我们在软件工程中进行的架构设计、模块实现、编码等工作,很多时候说到底就是围绕一件事进行:解耦。三层架构,MVC,微服务,DDD.我们分

大道至简

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

三层架构,MVC,微服务,DDD.我们分析问题,抽象问题,然后划分边界,划分层次。

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

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

什么是依赖?

通常可以理解为一种需要,需求。需要协助才能完成一件事情。

例如,我们依赖日志服务写日志:

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个接口,只是简单提供了调用能力,对于接口的编排全部寄希望于业务系统。

这个时候会有两种声音:

1、业务系统不想这么繁琐地重复着编排这些接口

2、中台也想把流程控制权掌握在自己手中,这样遇到业务流程的整体性变更,业务系统是不需要调整的

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

技术图片

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

模式

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

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

如果框架仅仅是给i我们提供类似于类库一样的MVC实现,

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

技术图片

所以,现在的Asp.Net Core 给我们提供的MVC,只要是我们遵循mvc约定,引擎就会推动整个信息的流动,最终反馈给应用。

这种比较普适的流程或者方案,我们可以成为模式,类似于设计模式,MVC模式.

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

总结

依赖倒置可以很小也可以很大,

控制反转也可以很小也可以很大。

这种思想我们无时无刻可以碰到。


推荐阅读
  • 本文介绍了深入浅出Linux设备驱动编程的重要性,以及两种加载和删除Linux内核模块的方法。通过一个内核模块的例子,展示了模块的编译和加载过程,并讨论了模块对内核大小的控制。深入理解Linux设备驱动编程对于开发者来说非常重要。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • 在Oracle11g以前版本中的的DataGuard物理备用数据库,可以以只读的方式打开数据库,但此时MediaRecovery利用日志进行数据同步的过 ... [详细]
  • MySQL数据库锁机制及其应用(数据库锁的概念)
    本文介绍了MySQL数据库锁机制及其应用。数据库锁是计算机协调多个进程或线程并发访问某一资源的机制,在数据库中,数据是一种供许多用户共享的资源,如何保证数据并发访问的一致性和有效性是数据库必须解决的问题。MySQL的锁机制相对简单,不同的存储引擎支持不同的锁机制,主要包括表级锁、行级锁和页面锁。本文详细介绍了MySQL表级锁的锁模式和特点,以及行级锁和页面锁的特点和应用场景。同时还讨论了锁冲突对数据库并发访问性能的影响。 ... [详细]
  • 本文详细介绍了SQL日志收缩的方法,包括截断日志和删除不需要的旧日志记录。通过备份日志和使用DBCC SHRINKFILE命令可以实现日志的收缩。同时,还介绍了截断日志的原理和注意事项,包括不能截断事务日志的活动部分和MinLSN的确定方法。通过本文的方法,可以有效减小逻辑日志的大小,提高数据库的性能。 ... [详细]
  • 本文介绍了在Python3中如何使用选择文件对话框的格式打开和保存图片的方法。通过使用tkinter库中的filedialog模块的asksaveasfilename和askopenfilename函数,可以方便地选择要打开或保存的图片文件,并进行相关操作。具体的代码示例和操作步骤也被提供。 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 使用Ubuntu中的Python获取浏览器历史记录原文: ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 本文介绍了作者在开发过程中遇到的问题,即播放框架内容安全策略设置不起作用的错误。作者通过使用编译时依赖注入的方式解决了这个问题,并分享了解决方案。文章详细描述了问题的出现情况、错误输出内容以及解决方案的具体步骤。如果你也遇到了类似的问题,本文可能对你有一定的参考价值。 ... [详细]
  • HDFS2.x新特性
    一、集群间数据拷贝scp实现两个远程主机之间的文件复制scp-rhello.txtroothadoop103:useratguiguhello.txt推pushscp-rr ... [详细]
  • 使用eclipse创建一个Java项目的步骤
    本文介绍了使用eclipse创建一个Java项目的步骤,包括启动eclipse、选择New Project命令、在对话框中输入项目名称等。同时还介绍了Java Settings对话框中的一些选项,以及如何修改Java程序的输出目录。 ... [详细]
  • 本文介绍了ASP.NET Core MVC的入门及基础使用教程,根据微软的文档学习,建议阅读英文文档以便更好理解,微软的工具化使用方便且开发速度快。通过vs2017新建项目,可以创建一个基础的ASP.NET网站,也可以实现动态网站开发。ASP.NET MVC框架及其工具简化了开发过程,包括建立业务的数据模型和控制器等步骤。 ... [详细]
author-avatar
x深藏的爱x_402
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有