依赖倒置 DIP
我们先来看看传统的三层架构,如下图所示:
从上图中我们可以看到:在传统的三层架构中,层与层之间是相互依赖的,UI层依赖于BLL层,BLL层依赖于DAL层。分层的目的是为了实现“高内聚、低耦合”。传统的三层架构只有高内聚没有低耦合,层与层之间是一种强依赖的关系,这也是传统三层架构的一种缺点。这种自上而下的依赖关系会导致级联修改,如果低层发生变化,可能上面所有的层都需要去修改,而且这种传统的三层架构也很难实现团队的协同开发,因为上层功能取决于下层功能的实现,下面功能如果没有开发完成,则上层功能也无法进行。
传统的三层架构没有遵循依赖倒置原则(DIP)来设计,所以就会出现上面的问题。
主要有两层含义:
1. 高层次的模块不应该依赖低层次的模块,两者都应该依赖其抽象。
2. 抽象不应该依赖于具体,具体应该依赖于抽象。
我们先来解释第一句话:高层模块不应该直接依赖低层模块的具体实现,而是应该依赖于低层模块的抽象,也就是说,模块之间的依赖是通过抽象发生的,实现类之间不应该发生直接的依赖关系,他们的依赖关系应该通过接口或者抽象类产生。
在来解释第二句话:接口或者抽象类不应该依赖于实现类。举个例子,假如我们要写BLL层的代码,直接就去实现了功能,等到开发完成以后发现没有使用依赖倒置原则,这时候在根据实现类去写接口,这种是不对的,应该首先设计抽象,然后在根据抽象去实现,应该要面向接口编程。
我们在上面说过,在传统的三层架构里面没有使用依赖倒置原则,那么把依赖倒置原则应用到传统的三层架构里面会如何呢?我们知道,在传统的三层架构里面,UI层直接依赖于BLL层,BLL层直接依赖于DAL层,由于每一层都是依赖下一层的实现,所以说当下层发生变化的时候,它的上一层也要发生变化,这时候可以根据依赖倒置原则来重新设计三层架构。
UI、BLL、DAL三层之间应该没有直接的依赖关系,都应该依赖于接口。首先应该先确定出接口,DAL层抽象出IDAL接口,BLL层抽象出IBLL接口,这样UI层依赖于IBLL接口,BLL实现IBLL接口。BLL层依赖于IDAL接口,DAL实现IDAL接口。如下图所示:
我们上面讲了依赖倒置原则,那么依赖倒置原则的目的是什么呢?
有了依赖倒置原则,可以使我们的架构更加的稳定、灵活,也能更好地应对需求的变化。相对于细节的多变性,抽象的东西是稳定的。所以以抽象为基础搭建起来的架构要比以细节为基础搭建起来的架构要稳定的多。
在传统的三层架构里面,仅仅增加一个接口层,我们就实现了依赖倒置,目的就是降低层与层之间的耦合。有了这样的接口层,三层架构才真正实现了“高内聚、低耦合”的思想。
先搭好基础架构:
创建好解决方案 -> 就添加实体
添加一个 类库 -> 添加 ConfigurationManager 类 ,一会用来读取 appsettings.json 配置文件
Nuget 引用3个包
Microsoft.Extensions.Configuration
Microsoft.Extensions.Configuration.FileExtensions
Microsoft.Extensions.Configuration.Json
添加 DAL 类库 ,添加 IDAL接口 和 和 DAL实现类 ,直接返回测试数据
添加 BLL 类库 ,添加 IBLL接口 和 和 BLL实现类 ,UserBLL 构造函数接收 IDAL
添加控制台项目 -> 添加 json 配置文件 内容
添加 Factory 类
基础架构基本就到这里完成了,可以正式的看看如何解耦操作的。
先在控制台输出底层数据,看看程序有没有问题
正常输出了底层 UserModel 的 Name 属性
这时候如果需求要改DAL成读MySql数据库
添加一个MySql 底层数据。在 属性 Name 加个标识
修改配置文件。只用修改红线,改为新添加的 mysql 类名
在以前的三层就要修改BLL层,如果项目多就改动越大。这里我们只要改配置文件就可以实现,这样就解耦了。
这时候如果需求要BLL要升级一个版本呢
添加一个 BLLV2 类库 , 同样继承 IBLL接口,其它一样方法一样实现
修改配置文件。只用修改红线,改为V2的BLL项目和实现类
生成运行,可以看到还是正常输出
接着调试,可以看到这里BLL调用的是BLLV2
网友评论