C#实现六大设计原则之依赖倒置原则
作者:痕迹g 发布时间:2023-06-27 04:02:57
依赖倒置原则(DIP)定义:
高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。
问题由来:
类A直接依赖类B,假如要将类A改为依赖类C,则必须通过修改类A的代码来达成。这种场景下,类A一般是高层模块,
负责复杂的业务逻辑;类B和类C是低层模块,负责基本的原子操作;假如修改类A,会给程序带来不必要的风险。
解决方案:
将类A修改为依赖接口I,类B和类C各自实现接口I,类A通过接口I间接与类B或者类C发生联系,则会大大降低修改类A的几率。
ps:
依赖倒置原则基于这样一个事实:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建起来的架构比以细节为基础
搭建起来的架构要稳定的多。抽象指的是接口或者抽象类,细节就是具体的实现类,使用接口或者抽象类的目的是制定
好规范和契约,而不去涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。
依赖倒置原则的核心思想是面向接口编程,用一个例子来说明面向接口编程比相对于面向实现编程好在什么地方。
举个生活中的例子, 我们每天下班, 可能为了方便亦或锻炼身体, 选择骑单车回家, 对于现在单车, 又有各种各样: mobike, ofo, 小蓝, 小鸣等等...
(用C#代码表达) 定义3个实现, 分别对应的是各种单车品牌。
public class BlueGoGo
{
public void Go()
{
Console.WriteLine("骑的是小蓝单车");
}
}
public class Ofo
{
public void Go()
{
Console.WriteLine("骑的是小黄单车");
}
}
public class Mobike
{
public void Go()
{
Console.WriteLine("骑的是摩拜单车");
}
}
然后再定义一个骑行类(Ride)
//骑行类
public class Ride
{
//扫码小蓝骑车
public void ScanCodeByBlueGoGo()
{
BlueGoGo blue = new BlueGoGo();
blue.Go();
}
//扫码摩拜单骑车
public void ScanCodeByMoBike()
{
Mobike mo = new Mobike();
mo.Go();
}
//扫码小黄骑车
public void ScanCodeByOfo()
{
Ofo ofo = new Ofo();
ofo.Go();
}
}
现在看上去确实也没什么问题, 所以调用一下, 一切正常
仔细看看, 这个代码确实有问题, 针对上面所讲的依赖倒置原则
<类A直接依赖类B, 假如要将类A改为依赖类C,则必须通过修改类A的代码来达成。这种场景下,类A一般是高层模块,负责复杂的业务逻辑;类B和类C是低层模块,负责基本的原子操作;假如修改类A,会给程序带来不必要的风险。>
正如例子中的 骑行类(Ride) 正是依赖BlueGoGo,MoBike,Ofo类, 如果现在 Ride类要新增一个小鸣单车, 则我们必须要修改Ride的代码,同是添加一个XiaoMing的类达到效果。
//骑行类
public class Ride
{
//扫码小蓝骑车
public void ScanCodeByBlueGoGo()
{
BlueGoGo blue = new BlueGoGo();
blue.Go();
}
//扫码摩拜单骑车
public void ScanCodeByMoBike()
{
Mobike mo = new Mobike();
mo.Go();
}
//扫码小黄骑车
public void ScanCodeByOfo()
{
Ofo ofo = new Ofo();
ofo.Go();
}
/*
* 该功能位新增的小鸣单车, 必须修改Ride类
*/
public void ScanCodeByXiaoMing()
{
XiaoMing xming = new XiaoMing();
xming.Go();
}
}
像MoBike, BlueGoGo, Ofo, XiaoMing 这些类, 他们都属于底层模块, 负责基本的骑车的动作, 按照依赖倒置的原则, 则不应该修改A, 否则如果在业务量很大的情况下, 则会给程序带来不必要的潜在风险。
用依赖导致的思想怎么去实现 新增小鸣单车而不对高层模块进行修改?
1.将单车的每个Go动作都抽象起来, 分别让他们去做各自的实现。
//修改位抽象的车类
public abstract class abstarctBike
{
public abstract void Go();
}
public class BlueGoGo: abstarctBike
{
public override void Go()
{
Console.WriteLine("骑的是小蓝单车");
}
}
public class Ofo : abstarctBike
{
public override void Go()
{
Console.WriteLine("骑的是小黄单车");
}
}
public class Mobike : abstarctBike
{
public override void Go()
{
Console.WriteLine("骑的是摩拜单车");
}
}
public class XiaoMing : abstarctBike
{
public override void Go()
{
Console.WriteLine("骑的是小明单车");
}
}
这时, 我们再把骑行类(Ride)进行改造, 将原有的ScanCodeXXX 都弃用, 用一个全新的ScanCode提供一个抽象类型。
//骑行类
public class Ride
{
//
public void ScanCode(abstarctBike bike)
{
bike.Go();
}
/*
* 以下位之前弃用的模式
*/
//扫码小蓝骑车
public void ScanCodeByBlueGoGo()
{
BlueGoGo blue = new BlueGoGo();
blue.Go();
}
//扫码摩拜单骑车
public void ScanCodeByMoBike()
{
Mobike mo = new Mobike();
mo.Go();
}
//扫码小黄骑车
public void ScanCodeByOfo()
{
Ofo ofo = new Ofo();
ofo.Go();
}
/*
* 该功能位新增的小鸣单车, 必须修改Ride类
*/
public void ScanCodeByXiaoMing()
{
XiaoMing xming = new XiaoMing();
xming.Go();
}
}
现在, 我们再调用, 只要指定给Ride对象ScanCode执行的类型就可以实现骑行动作。
这样修改后,无论以后怎样扩展单车类,都不需要再修改Ride类了。这只是一个简单的例子,实际情况中,代表高层模块的Ride类将负责完成主要的业务逻辑,
一旦需要对它进行修改,引入错误的风险极大。所以遵循依赖倒置原则可以降低类之间的耦合性,提高系统的稳定性,降低修改程序造成的风险。
在实际编程中,我们一般需要做到如下3点:
低层模块尽量都要有抽象类或接口,或者两者都有。
变量的声明类型尽量是抽象类或接口。
使用继承时遵循里氏替换原则。
依赖倒置原则的核心就是要我们面向接口编程,理解了面向接口编程,也就理解了依赖倒置。
来源:https://www.cnblogs.com/zh7791/p/7921345.html


猜你喜欢
- 1.先通过程序生成报表样式的HTML页面,然后修改HTML页面的后缀名为DOC。 2.定制WORD文档的模板文件,在C#中操作WORD模板,
- 1.shiro安全框架Apache Shiro 是一个强大易用的 Java 安全框架,提供了认证、授权、加密和session会话管理等功能,
- progressDialog, 它有两个方法dialog.cancel() 和 dialog.dimiss()1. public void
- 关于Fresco的优点大家自行谷歌吧,它太强大太优秀了,我这一片小博文容纳不下啊羡慕,今天主要给大家简单介绍下Fresco的使用以及一些属性
- 本文不再对值类型进行讨论,主要讨论一下引用类型。如要看内存值类型的朋友可以看一下前一篇C#之CLR内存原理初探。C#引用类型具体分析如下:先
- 本文实例为大家分享了java实现简单年龄计算器的具体代码,供大家参考,具体内容如下制作一个如下图年龄计算器根据题目,我做了一个由Calend
- 一、单链表(Linked List)简介二、单链表的各种操作1.单链表的创建和遍历2.单链表的按顺序插入节点 以及节点的修改3.单链表节点的
- 收费版本:Rainbow Brackets免费版本:Rainbow Brackets Lite介绍一款可以将 (圆括号) [方括号] {花括
- 1)打开idea,开始创建SpringBoot项目2)选择 Spring Initializr ,选择合适的jdk版本,点击Next在操作到
- java自定义切面增强写代码时会遇到一些有些重复机械的工作, 这个时候就可以运用切面技术来帮我们节约时间介绍如何使用自定义注解增强方法, 实
- 本人没有接触android开发,由于想学习一下,所以自学,接下来是我学习路线,希望我走过的路能给你提供帮助。 下载首先我们需要下载 Andr
- 面试题1:说说什么分布式事务?解释一下什么是CAP?现在互联网开发多使用微服务架构,一个简单的操作,在服务端可能就是由多个服务和数据库实例协
- 本文实例为大家分享了java使用influxDB数据库的具体代码,供大家参考,具体内容如下1.pom.xml中导入jar包依赖<!--
- 本文实例为大家分享了用JavaMail发送HTML模板邮件的具体代码,供大家参考,具体内容如下依赖<dependency>&nb
- Java栈之链式栈存储结构实现一、链栈采用单链表来保存栈中所有元素,这种链式结构的栈称为链栈。二、栈的链式存储结构实现package com
- 异常算术异常类:ArithmeticExecption空指针异常类:NullPointerException类型强制转换异常:ClassCa
- 之前做 Ble 开发都是在 Android 6.0 系统以下的版本中进行测试的,今天使用 Android 6.0 的设备测试的时候,发现扫描
- 问题描述最近IDEA抽风了,不管是新建SpringBoot工程,还是导入项目。IDEA代码里面都会飘红~Build项目时,会提示错误:错误:
- 通常我们遇到的图片缩放需求,都是图片基于屏幕自适应后,进行缩放和移动,且图片最小只能是自适应的大小。最近遇到一个需求,要求图片只能在屏幕内缩
- 前言此文章主要解决拦截用户点击手机底部导航栏中的返回键时该事件的拦截;此方法依然可以适用于fragmentonBackPressed()这是