返回顶部
首页 > 资讯 > 精选 >C#中依赖倒置原则DIP的示例分析
  • 355
分享到

C#中依赖倒置原则DIP的示例分析

2023-06-29 14:06:45 355人浏览 泡泡鱼
摘要

这篇文章主要介绍C#中依赖倒置原则DIP的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、前言我们先来看看传统的三层架构,如下图所示:从上图中我们可以看到:在传统的三层架构中,层与层之间是相互依赖的,UI层

这篇文章主要介绍C#中依赖倒置原则DIP的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!

一、前言

我们先来看看传统的三层架构,如下图所示:

C#中依赖倒置原则DIP的示例分析

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

传统的三层架构没有遵循依赖倒置原则(DIP)来设计,所以就会出现上面的问题。

二、依赖倒置

依赖倒置(DIP):Dependence Inversion Principle的缩写,主要有两层含义:

  • 高层次的模块不应该依赖低层次的模块,两者都应该依赖其抽象。

  • 抽象不应该依赖于具体,具体应该依赖于抽象。

我们先来解释第一句话:高层模块不应该直接依赖低层模块的具体实现,而是应该依赖于低层模块的抽象,也就是说,模块之间的依赖是通过抽象发生的,实现类之间不应该发生直接的依赖关系,他们的依赖关系应该通过接口或者抽象类产生。

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

我们在上面说过,在传统的三层架构里面没有使用依赖倒置原则,那么把依赖倒置原则应用到传统的三层架构里面会如何呢?我们知道,在传统的三层架构里面,UI层直接依赖于BLL层,BLL层直接依赖于DAL层,由于每一层都是依赖下一层的实现,所以说当下层发生变化的时候,它的上一层也要发生变化,这时候可以根据依赖倒置原则来重新设计三层架构。

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

C#中依赖倒置原则DIP的示例分析

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

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

依赖倒置原则是架构层面上的,那么如何在代码层面上实现呢?下面看控制反转。

三、控制反转

控制反转(ioc):Inversion of Control的缩写,一种反转流、依赖和接口的方式,它把传统上由程序代码直接操控的对象的控制器(创建、维护)交给第三方,通过第三方(IOC容器)来实现对象组件的装配和管理。

IOC容器,也可以叫依赖注入框架,是由一种依赖注入框架提供的,主要用来映射依赖,管理对象的创建和生存周期。IOC容器本质上就是一个对象,通常会把程序里面所有的类都注册进去,使用这个类的时候,直接从容器里面去解析。

四、依赖注入

依赖注入(DI):Dependency Injection的缩写。依赖注入是控制反转的一种实现方式,依赖注入的目的就是为了实现控制反转。

依赖注入是一种工具或手段,目的是帮助我们开发出松耦合、可维护的程序。

依赖注入常用的方式有以下几种:

  • 构造函数注入。

  • 属性注入。

  • 方法注入。

其中构造函数注入是使用最多的,其次是属性注入。

看下面的一个例子:父亲给孩子讲故事,只要给这个父亲一本书,他就可以照着这本书给孩子讲故事。我们下面先用最传统的方式实现一下,这里不使用任何的设计原则和设计模式

首先定义一个Book类:

namespace DipDemo1{    public class Book    {        public string GetContent()        {            return "从前有座山,山上有座庙.....";        }    }}

然后在定义一个Father类:

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

然后在Main方法里面调用:

using System;namespace DipDemo1{    class Program    {        static void Main(string[] args)        {            Father father = new Father();            father.Read();            Console.ReadKey();        }    }}

我们来看看关系图:

C#中依赖倒置原则DIP的示例分析

我们看到:Father是直接依赖于Book类。

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

namespace DipDemo1{    public class NewsPaper    {        public string GetContent()        {            return "新闻";        }    }}

这时依赖关系变了,因为爸爸要依赖于报纸了,这就导致还要修改Father类:

using System;namespace DipDemo1{    public class Father    {        public void Read()        {            // 读书            // Book book = new Book();            //Console.WriteLine("爸爸开始给孩子讲故事了");            //Console.WriteLine(book.GetContent());            // 报纸            NewsPaper paper = new NewsPaper();            Console.WriteLine("爸爸开始给孩子讲新闻");            Console.WriteLine(paper.GetContent());        }    }}

假设后面需求又变了,又不给报纸了,换成杂志、平板电脑等。需求在不断的变化,不管怎么变化,对于爸爸来说,他一直在读读物,但是具体读什么读物是会发生变化,这就是细节,也就是说细节会发生变化。但是抽象是不会变的。如果这时候还是使用传统的OOP思想来解决问题,那么会导致程序不断的在修改。下面使用工厂模式来优化

首先创建一个接口:

namespace DipDemo2{    public interface IReader    {        string GetContent();    }}

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

namespace DipDemo2{    public class Book : IReader    {        public string GetContent()        {            return "从前有座山,山上有座庙.....";        }    }}

NewsPaper类:

namespace DipDemo2{    public class NewsPaper : IReader    {        public string GetContent()        {            return "王聪聪被限制高消费......";        }    }}

然后创建一个工厂类:

namespace DipDemo2{    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类里面调用工厂类:

using System;namespace DipDemo2{    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());        }    }}

最后在Main方法里面调用:

using System;namespace DipDemo2{    class Program    {        static void Main(string[] args)        {            Father father = new Father("Book");            father.Read();            Console.ReadKey();        }    }}

我们这时候可以在看看依赖关系图:

C#中依赖倒置原则DIP的示例分析

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

下面继续优化代码,这里只需要修改Father类:

using System;namespace DipDemo3{    public class Father    {        public IReader Reader { get; set; }        /// <summary>        /// 构造函数的参数是IReader接口类型        /// </summary>        /// <param name="reader"></param>        public Father(IReader reader)        {            Reader = reader;        }        public void Read()        {            Console.WriteLine("爸爸开始给孩子讲故事了");            Console.WriteLine(Reader.GetContent());        }    }}

在Main方法里面调用:

using System;namespace DipDemo3{    class Program    {        static void Main(string[] args)        {            var f = new Father(new Book());            f.Read();            Console.ReadKey();        }    }}

如果以后换成了Paper,需要修改代码:

using System;namespace DipDemo3{    class Program    {        static void Main(string[] args)        {            // Book            //var f = new Father(new Book());            //f.Read();            // Paprer            var f = new Father(new Paper());            f.Read();            Console.ReadKey();        }    }}

由于这里没有了工厂,我们还是需要在代码里面实例化具体的实现类。如果有一个IOC容器,我们就不需要自己new一个实例了,而是由容器帮我们创建实例,创建完成以后在把依赖对象注入进去。

我们在来看一下依赖关系图:

C#中依赖倒置原则DIP的示例分析

下面我们使用Unity容器来继续优化上面的代码,首先需要在项目里面安装Unity,直接在NuGet里面搜索即可:

C#中依赖倒置原则DIP的示例分析

这里只需要修改Main方法调用即可:

using System;using Unity;namespace UnityDemo{    class Program    {        static void Main(string[] args)        {            // 创建容器            var container = new UnityContainer();            // 扫描程序集、配置文件            // 在容器里面注册接口和实现类,创建依赖关系            container.ReGISterType<IReader, Book>();            // 在容器里面注册Father            container.RegisterType<Father>();            // 从容器里拿出要使用的类,容器会自行创建father对            // 还会从容器里去拿到他所依赖的对象,并且注入进来            //             var father = container.Resolve<Father>();            // 调用方法            father.Read();            Console.ReadKey();        }    }}

以上是“C#中依赖倒置原则DIP的示例分析”这篇文章的所有内容,感谢各位的阅读!希望分享的内容对大家有帮助,更多相关知识,欢迎关注编程网精选频道!

--结束END--

本文标题: C#中依赖倒置原则DIP的示例分析

本文链接: https://lsjlt.com/news/325238.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • C#中依赖倒置原则DIP的示例分析
    这篇文章主要介绍C#中依赖倒置原则DIP的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!一、前言我们先来看看传统的三层架构,如下图所示:从上图中我们可以看到:在传统的三层架构中,层与层之间是相互依赖的,UI层...
    99+
    2023-06-29
  • C#编程之依赖倒置原则DIP
    一、前言 我们先来看看传统的三层架构,如下图所示: 从上图中我们可以看到:在传统的三层架构中,层与层之间是相互依赖的,UI层依赖于BLL层,BLL层依赖于DAL层。分层的目的是为了...
    99+
    2024-04-02
  • Java依赖倒置原则案例分析
    今天小编给大家分享一下Java依赖倒置原则案例分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。定义依赖倒转原则,又称依赖倒...
    99+
    2023-06-29
  • 深入浅析python3 依赖倒置原则(示例代码)
    场景 针对园区停车信息,需要对各个公司提供的停车数据进行整合并录入自家公司的大数据平台 数据的录入无外乎就是对数据的增删改查 下面上一个常规的写法(未符合依赖倒置),整合来自 长安...
    99+
    2024-04-02
  • C#实现六大设计原则之依赖倒置原则
    依赖倒置原则(DIP)定义: 高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。 问题由来: 类A直接依赖类B,假如要将类A改为依赖类C,则必须...
    99+
    2024-04-02
  • java的依赖倒置原则你了解多少
    目录依赖倒置原则案例:背景:1.面向实现编程2.面向接口编程(简单版)总结依赖倒置原则 什么是依赖倒置原则: 高层模块不应该依赖低层模块,二者都应该依赖其抽象 抽象不应该依赖细节,细...
    99+
    2024-04-02
  • springboot中maven配置依赖的示例分析
    这篇文章主要介绍springboot中maven配置依赖的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!具体如下:我们通过引用spring-boot-starter-parent,添加spring-boot-...
    99+
    2023-05-30
    springboot maven
  • C++依赖倒转原则和里氏代换原则的作用是什么
    这篇“C++依赖倒转原则和里氏代换原则的作用是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“C++依赖倒转原则和里氏代换...
    99+
    2023-07-05
  • Vue中依赖注入的示例分析
    这篇文章主要介绍了Vue中依赖注入的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。简单粗暴型:<el-select ...
    99+
    2024-04-02
  • Angular中依赖注入的示例分析
    这篇文章主要介绍Angular中依赖注入的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!依赖注入:设计模式依赖:程序里需要的某种类型的对象。依赖注入框架:工程化的框架注入器Injector:用它的API创建依...
    99+
    2023-06-06
  • java设计模式的依赖倒置原则怎么实现
    这篇文章主要讲解了“java设计模式的依赖倒置原则怎么实现”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“java设计模式的依赖倒置原则怎么实现”吧!依赖倒置原则(Dependence Inv...
    99+
    2023-06-17
  • RequireJS依赖关系的示例分析
    这篇文章主要介绍RequireJS依赖关系的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!下面有个html页面:<html>   <he...
    99+
    2024-04-02
  • Angular4依赖注入的示例分析
    这篇文章给大家分享的是有关Angular4依赖注入的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。基础知识Angular CLI 基本使用1、安装 Angular CLI...
    99+
    2024-04-02
  • Spring依赖注入的示例分析
    这篇文章给大家分享的是有关Spring依赖注入的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。一.依赖简介一个典型的企业应用程序不是由一个单一的对象组成(或Spring的说法中的bean)。即使是最简单的...
    99+
    2023-06-03
  • C#面向对象编程中依赖反转原则的示例详解
    在面向对象编程中,SOLID 是五个设计原则的首字母缩写,旨在使软件设计更易于理解、灵活和可维护。这些原则是由美国软件工程师和讲师罗伯特·C·马...
    99+
    2024-04-02
  • Spring Boot配置排序依赖技巧的示例分析
    这篇文章主要介绍Spring Boot配置排序依赖技巧的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!具体如下:Spring Boot - 被错误使用的注解我自己曾经在 Spring Boot 中集成通用 M...
    99+
    2023-05-30
    spring boot
  • Angular6中服务和依赖注入的示例分析
    这篇文章主要介绍Angular6中服务和依赖注入的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!在开发中,组件一般用来写视图有关的功能,服务则写一些其他的逻辑,诸如从服务器获...
    99+
    2024-04-02
  • SpringBoot中@Async引起循环依赖的示例分析
    这篇文章将为大家详细讲解有关SpringBoot中@Async引起循环依赖的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。事故时间线本着"先止损、后复盘分析"的原则,我们来看一...
    99+
    2023-06-29
  • golang依赖管理之mod的示例分析
    这篇文章主要介绍了golang依赖管理之mod的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。golang 依赖管理之 modgo 很早就考虑了依赖管理的问题,内置 ...
    99+
    2023-06-14
  • Spring解决循环依赖的示例分析
    这篇文章主要介绍Spring解决循环依赖的示例分析,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!  这里我们先借用一张图来通过视觉感受一下,看图:    其实,通过上面图片我想你应该能看图说话了,所谓的循环依赖其实就...
    99+
    2023-06-25
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作