C# 依赖倒置原则(DIP)

news2024/11/25 0:45:32

目录

一,引子

1.1 传统的程序架构

1.2 依赖倒置

1.3 依赖倒置的作用

二,依赖注入


一,引子

1.1 传统的程序架构

在程序执行过程中,传统的程序架构如图:

可以看到,在传统的三层架构中,层与层之间是相互依赖的,UI层依赖于BLL层,BLL层依赖于DAL层。分层的目的是为了实现“高内聚、低耦合”。传统的三层架构只有高内聚没有低耦合,层与层之间是一种强依赖的关系,这也是传统三层架构的一种缺点。这种自上而下的依赖关系会导致级联修改,如果低层发生变化,可能上面所有的层都需要去修改,而且这种传统的三层架构也很难实现团队的协同开发,因为上层功能取决于下层功能的实现,下面功能如果没有开发完成,则上层功能也无法进行。

1.2 依赖倒置

依赖倒置(DIP):Dependence Inversion Principle的缩写,是一种软件架构设计的原则(抽象概念)。依赖于抽象不依赖于细节。主要有两层含义:

  1. 高层次的模块不应该依赖低层次的模块,两者都应该依赖其抽象。
  2. 抽象不应该依赖于具体,具体应该依赖于抽象。

如何理解这两句话?

  • 第一句话:模块之间的依赖是通过抽象发生的,实现类之间不应该发生直接的依赖关系,他们的依赖关系应该通过接口或者抽象类产生。
  • 第二句话:举个例子,假如我们要写BLL层的代码,直接就去实现了功能,等到开发完成以后发现没有使用依赖倒置原则,这时候在根据实现类去写接口,这种是不对的,应该首先设计抽象,然后在根据抽象去实现,应该要面向接口编程。

 根据依赖倒置原则重新设计代码执行架构:

UI、BLL、DAL三层之间应该没有直接的依赖关系,都应该依赖于接口。首先应该先确定出接口,DAL层抽象出IDAL接口,BLL层抽象出IBLL接口,这样UI层依赖于IBLL接口,BLL实现IBLL接口。BLL层依赖于IDAL接口,DAL实现IDAL接口。如下图所示:

1.3 依赖倒置的作用

有了依赖倒置原则,可以使我们的架构更加的稳定、灵活,也能更好地应对需求的变化。相对于细节的多变性,抽象的东西是稳定的。所以以抽象为基础搭建起来的架构要比以细节为基础搭建起来的架构要稳定的多。

在传统的三层架构里面,仅仅增加一个接口层,我们就实现了依赖倒置,目的就是降低层与层之间的耦合。有了这样的接口层,三层架构才真正实现了“高内聚、低耦合”的思想。

二,依赖注入

依赖倒置原则是架构层面上的,那么如何在代码层面上实现呢?这就需要用到控制反转IOC

传统开发,上端依赖(调用/指定)下端对象,会有依赖,把对下端对象的依赖转移到第三方容器(工厂+配置文件+反射),能够程序拥有更好的扩展性,是DIP的具体实现方式,可以用来减低计算机代码之间的耦合度。

依赖注入DI 是控制反转的一种实现方式。

  1. 是实现IOC的手段和方法,就是能做到构造某个对象时,将依赖的对象自动初始化并注入 :
  2. 有三种注入方式:构造函数注入--属性注入--方法注入(按时间顺序):
  3. 构造函数注入用的最多,默认找参数最多的构造函数,可以不用特性,可以去掉对容器的依赖

下面通过一个例子,对上述专业名词进行解释:

父亲给孩子讲故事,只要给这个父亲一本书,他就可以照着这本书给孩子讲故事。

  • 我们下面先用最传统的方式实现一下,这里不使用任何的设计原则和设计模式。

首先定义一个Book类:

 public class Book
    {
        public string GetContent()
        {
            return "门前大桥下,游过一群鸭";
        }
    }

然后定义父亲Father类:

 public class Father
    {
        public void read()
        {
            Book book = new Book();
            Console.WriteLine("爸爸开始给孩子讲故事了:");
            Console.WriteLine(book.GetContent());
        }
    }

主程序调用:

  static void Main(string[] args)
        {
            Father father = new Father();
            father.read();
            Console.ReadKey();
        }
//打印效果:
爸爸开始给孩子讲故事了:
门前大桥下,游过一群鸭

 我们来看看关系图:

可以看到:Father是直接依赖于Book类。

这时需求发生了变化,不给爸爸书了,给爸爸报纸,让爸爸照着报纸给孩子读报纸,这时该怎么做呢?按照传统的方式,我们这时候需要再定义一个报纸类,还要修改Father类。

但是需求在不断的变化,不管怎么变化,对于爸爸来说,他一直在读读物,但是具体读什么读物是会发生变化,这就是细节,也就是说细节会发生变化。但是抽象是不会变的。如果这时候还是使用传统的OOP思想来解决问题,那么会导致程序不断的在修改。

下面使用工厂模式来优化:

首先创建一个接口:

 public interface IReader
    {
        string GetContent();
    }

然后让Book类和NewsPaper类都继承自IReader接口

    public class Book:IReader
    {
        public string GetContent()
        {
            return "门前大桥下,游过一群鸭";
        }
    }
    public class NewsPaper : IReader
    {
        public string GetContent()
        {
            return "7月3日是地球上有记录以来最热的一天";
        }
    }

 之后创建一个工厂类:

public static class ReaderFactory
    {
        public static IReader GetReader(string readerType)
        {
            if (string.IsNullOrEmpty(readerType))
            {
                return null;
            }
            switch(readerType)
            {
                case "NewsPaper":
                    return new NewsPaper();
                case "Book":
                    return new Book();
                default:
                    return null;
            }
        }
    }

里面方法的返回值是一个接口类型。最后在Father类里面调用工厂类:

public class Father
    {
        private IReader reader { get; set; }
        public Father(string readerName)
        {
            reader = ReaderFactory.GetReader(readerName);
        }
        public void read()
        {
            Console.WriteLine("爸爸开始给孩子讲故事了:");
            Console.WriteLine(reader.GetContent());
        }
    }

 最后在主程序调用:

 static void Main(string[] args)
        {
            Father father = new Father("NewsPaper");
            father.read();
            Console.ReadKey();
        }
//打印效果:
爸爸开始给孩子讲故事了:
7月3日是地球上有记录以来最热的一天

此时的依赖关系图:

这时Father已经和Book、Paper没有任何依赖了,Father依赖于IReader接口,还依赖于工厂类,而工厂类又依赖于Book和Paper类。这里实际上已经实现了控制反转。Father(高层)不依赖于低层(Book、Paper)而是依赖于抽象(IReader),而且具体的实现也不是由高层来创建,而是由第三方来创建(这里是工厂类)。但是这里只是使用工厂模式来模拟控制反转,而没有实现依赖的注入,依赖还是需要向工厂去请求。

再进一步优化代码 

 

 由于此时没有了工厂,我们还是需要在主程序调用中实例化具体的实现类。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/721355.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CSS的学习4(盒子模型及浮动)

CSS的学习3:http://t.csdn.cn/xDxIJ 盒子模型 网页布局过程 先准备好相关的网页元素,网页元素基本都是盒子Box利用CSS设置好盒子样式,然后摆放到相应位置往盒子里面装内容 封装周围的HTML元素: 边框(border&#…

[网鼎杯 2020 青龙组]AreUSerialz1

代码审计 得到一大串源码&#xff0c;但是不要慌&#xff0c;虽然源码很多&#xff0c;其实题目并不难 这段代码是一个简单的文件读写类 FileHandler&#xff0c;以及一个反序列化函数 unserialize() 的使用。 <?phpinclude("flag.php");highlight_file(__FILE__…

Stable Diffusion 中英文对照中文tag补全

Stable Diffusion是老外做的&#xff0c;因此全部界面都是英文的&#xff0c;因此会对国内很多英语不好的小伙伴来说是一个灾难&#xff0c;不过这里介绍大家一个自定义翻译插件的方法如下图。 还有我们在输入关键词的时候&#xff0c;由于英语水平有限对我们造成阻碍&#xf…

QTTCP客户端服务端通信

目录 网络模块介绍 TCP介绍 TCP 服务端应用实例 TCP 客户端应用实例 运行结果&#xff1a; 网络模块介绍 Qt 网络模块为我们提供了编写 TCP / IP 客户端和服务器的类。它提供了较低级别的类&#xff0c;例 如代表低级网络概念的 QTcpSocket &#xff0c; QTcpServer 和 …

智慧旅游卡APP小程序开发方案

旅游业的蓬勃发展&#xff0c;旅游卡作为一种便捷的旅游支付方式越来越受到人们的喜爱。智慧旅游卡APP小程序开发方案是一种利用微信小程序实现的在线购买旅游卡、查询旅游信息、预约旅游服务等功能的旅游卡APP。下面将详细介绍智慧旅游卡APP小程序的开发方案。 一、智慧旅…

【CDC 2023 Cooperative Aerial Robots Inspection Challenge】

CDC 2023 Cooperative Aerial Robots Inspection Challenge 合作空中机器人检查挑战赛 Install the CARIC packagesRun the flight testThe benchmark designThe UAV fleet CDC 2023 Cooperative Aerial Robots Inspection Challenge 网址 Install the CARIC packages Once t…

旅游卡APP开发解决方案

旅游业的不断发展&#xff0c;旅游卡成为了人们出行时必不可少的一项工具。旅游卡APP开发解决方案旨在为用户提供更加便捷、高效的旅游卡购买和使用体验。下面将详细介绍旅游卡APP开发解决方案的几个方面。 一、旅游卡APP开发解决方案的技术方面 旅游卡APP开发解决方案…

Python pyecharts实时画图自定义可视化经纬度热力图

目录 背景基于pyecharts内置经纬度的热力图基于自定义经纬度的热力图pyecharts库缺点不同地图坐标系区别 WGS-84 - 世界大地测量系统GCJ-02 - 国测局坐标BD-09 - 百度坐标系 背景 在业务数据统计分析中基本都会涉及到各省区的分析&#xff0c;数据可视化是数据分析的一把利器…

事件机制(事件流、事件委托、事件类型)

HTML DOM 允许 JavaScript 对 HTML 事件作出反应。JavaScript 能够在事件发生时执行&#xff0c;比如当用户点击某个 HTML 元素时。 JavaScript与HTML之间的交互是通过事件实现的。事件就是文档或浏览器窗口中发生的一些特定的交互瞬间。 目录 事件是由三部分组成 执行事件的步…

儿童硅胶勺子LFGB标准检测是什么?

食品级硅胶制品的德国食品接触材料测试LFGB标准检测哪些项目&#xff1f; Sensory test感官测试一味道和气味对于与食品接触的整体产品 extractable components in ethanol(Ethanol as compulsory simulant)(must perform)10%酒精萃取法(必做) Extractable component in deioni…

官网能为企业营销增长贡献哪些力量?

官网是门面&#xff0c;同时也具备营销价值&#xff0c;可以带来流量转化成销售线索&#xff0c;影响公司营收&#xff0c;B2B业务是复杂的&#xff0c;客户在选择你之前会长期的研究你的官网&#xff0c;了解你的产品及服务、成功案例、甚至是品牌的创始团队信息&#xff0c;来…

SpringCloud学习1

SpringCloud是分布式微服务架构的 一些列解决方案的集合&#xff0c;SpringBoot是一门单独的技术 ​​​​​​

小心 MybatisPlus 的一个坑与面试题

昨天测试说有个 xx 功能用不了&#xff0c;扔给我一个截图&#xff0c;说有报错&#xff1a; 报错信息就是&#xff1a;Transaction rolled back because it has been marked as rollback-only&#xff0c;很好理解&#xff1a;事务被回滚了&#xff0c;因为它已经被标记了只能…

HttpRunner自动化之请求中带有 headers 的接口和发送POST请求

headers 可通过headers 添加头部信息&#xff0c;如下图 # 发送请求头headers的接口 - config:name: 百度接口用例base_url: https://www.baidu.com- test:name: 发送百度接口的头部信息request:url: /smethod: GETheaders:Accept: text/html,application/xhtmlxml,applicati…

LNMT(linux下nignx+mysql+tomcat(中间件)应用)部署应用、及各服务介绍、部署开源站点jpress

目录 一、环境准备 二、tomcat1和tomcat2服务器&#xff0c;安装配置tomcat 1.tomcat服务器介绍 2.JDK软件介绍 3.查看JDK是否安装 4.tomcat1和tomcat2服务器&#xff0c;安装JDK1.8.0_191&#xff08;JDK必须和nginx版本相适应&#xff0c;不然一直报错&#xff09; 5.安…

【LeetCode】HOT 100(21)

题单介绍&#xff1a; 精选 100 道力扣&#xff08;LeetCode&#xff09;上最热门的题目&#xff0c;适合初识算法与数据结构的新手和想要在短时间内高效提升的人&#xff0c;熟练掌握这 100 道题&#xff0c;你就已经具备了在代码世界通行的基本能力。 目录 题单介绍&#…

源启数据资产管理平台助力金融机构加速数据资产化过程

自2000年左右&#xff0c;金融行业开始做数据管理。从数据仓库到数据治理、数据应用&#xff0c;再到后来的大数据&#xff0c;以及今天的数据管理。我们把这个时期总结成数据资产化时代&#xff0c;或者叫国产化时代。 为什么有两个名字&#xff1f;数据资产化时代是因为国家…

关于PID闭环控制中上位机与下位机通讯代码的解析分享(一)

下位机接收数据代码&#xff08;以STM32单片机为例&#xff09;与上位机发送数据C#代码分享 1、下位机代码&#xff1a; /*** brief 接收的数据处理* param void* return -1&#xff1a;没有找到一个正确的命令.*/ int8_t receiving_process(void) {uint8_t frame_data[…

虚幻引擎程序化资源生成框架PCG 之 常用撒点方法小结

PCG真好玩&#xff0c;门槛很低&#xff0c;天花板很高 文章目录 前言1. 基本撒点1.1 Landscape上撒点1.2 使用射线检测在地表面撒点1.3 使用曲线撒点1.3.1 沿曲线撒点1.3.2 在闭合曲线内部撒点 1.4 在StaticMesh表面撒点 2. 进阶撒点2.1 在闭合曲线内部放射状撒点2.2 在Mesh表…

MedCalc v22.009 医学ROC曲线统计分析软详细图文教程

简介 MedCalc是一款医学 ROC 曲线统计软件&#xff0c;用于ROC曲线分析的参考软件&#xff0c;医学工作者设计的医学计算器&#xff0c;功能齐全。它可以帮助医生快速作出普通的医学计算&#xff0c;从而对症下药。提供超过76种常用的规则和方法&#xff0c;包括&#xff1a;病…