依赖倒转原则和里氏代换原则详解

news2024/9/26 1:26:12

初学依赖倒转原则和里氏代换原则时,由于笔者水平有限,并没有看懂书上的专业术语的解释,经过反复摸索和学习,发现里氏代换原则和依赖倒转原则可以一言以蔽之:

里氏代换原则:开发时以抽象为核心,针对抽象编程,能够抽象为一个抽象类或者接口的,就将其抽象为抽象类或者接口,然后用子类来进行实现

依赖倒转原则:将代码分为3层考虑,业务逻辑层,抽象层和实现层,其中业务逻辑层依赖抽象层,实现层也依赖抽象层

那么在代码中使用依赖倒转原则和里氏代换原则有什么好处吗?

只要能抽象你就进行抽象,然后不管高层模块(业务逻辑层)还是低层模块(实现层),它们都依赖于抽象,具体一点就是接口或抽象类,只要接口是稳定的,那么任何一个的更改都不用担心其他受到影响,即降低了耦合度。

光看理论,肯定还是一头雾水,下面通过一个例子来理清里氏代换原则和依赖倒转原则。

我们现在有张三司机和李四司机,有宝马和奔驰汽车,需求包括张三开宝马,李四开奔驰。

#include<iostream>
using namespace std;

class Benz
{
public:
	void run()
	{
		cout << "Benz is running" << endl;
	}
};

class BMW
{
public:
	void run()
	{
		cout << "BMW is runnning" << endl;
	}
};

class Zhang3
{
public:
	void driveBenz(Benz* benz)
	{
		cout << "zhang3 drives Benz" << endl;
		benz->run();
	}
};

class Li4
{
public:
	void driveBMW(BMW* bmw)
	{
		cout << "li4 drives BMW" << endl;
		bmw->run();
	}
};

int main()
{
	Benz benz;
	BMW bmw;
	Zhang3 zhang3;
	Li4 li4;
	zhang3.driveBenz(&benz);
	li4.driveBMW(&bmw);

	return 0;
}

那如果我们要拓展业务需求,张三既要开奔驰,也要开宝马,李四既要开奔驰也要开宝马,那也很简单,只需要在张三类和李四类中各增加一个方法即可。

#include<iostream>
using namespace std;

class Benz
{
public:
	void run()
	{
		cout << "Benz is running" << endl;
	}
};

class BMW
{
public:
	void run()
	{
		cout << "BMW is runnning" << endl;
	}
};

class Zhang3
{
public:
	void driveBenz(Benz* benz)
	{
		cout << "zhang3 drives Benz" << endl;
		benz->run();
	}

	void driveBMW(BMW* bmw)
	{
		cout << "zhang3 drives BMW" << endl;
		bmw->run();
	}
};

class Li4
{
public:
	void driveBenz(Benz* benz)
	{
		cout << "li4 drives Benz" << endl;
		benz->run();
	}

	void driveBMW(BMW* bmw)
	{
		cout << "li4 drives BMW" << endl;
		bmw->run();
	}
};

int main()
{
	Benz benz;
	BMW bmw;
	Zhang3 zhang3;
	Li4 li4;
	zhang3.driveBenz(&benz);
	zhang3.driveBMW(&bmw);
	li4.driveBenz(&benz);
	li4.driveBMW(&bmw);

	return 0;
}

这是一个耦合度极高的设计,那以后拓展了新功能,张三开丰田,李四开奥迪,那我得设计一个新丰田类,新奥迪类,然后在张三类中进行修改,在李四类中进行修改,我每次拓展新功能,都要修改其它模块中的内容,这样的一个设计显然是一个耦合度极高的设计。

如果一个系统有上百个模块,那么再添加一个新模块,新功能的时候,那可能还得修改几百个模块的内容,这样显然是极不方便的。

那如果我们利用里氏代换原则和依赖倒转原则,能抽象就抽象,并将代码分为3层考虑,分别是业务逻辑层,抽象层和实现层,具体思路就是将奔驰,宝马,丰田等等汽车抽象为一个汽车类,汽车类包含一个公共接口run,将张三,李四,王五等等人物抽象为一个人物类,人物类中包含一个公共接口drive,drive中的参数也是抽象的汽车类,然后假设我们需要李四开奔驰,我们就在实现层去实现一个具体的奔驰类,在实现层实现一个具体的李四类,然后在业务逻辑层创建一个李四对象,创建一个奔驰对象,将奔驰汽车对象传给李四对象中的drive方法,就实现了李四开奔驰,如果想要实现李四开宝马,那么同样,只需要在实现层新实现一个宝马类,然后去业务逻辑层创建一个宝马对象,再将宝马对象传给李四对象中的drive方法,就实现了李四开宝马,后面我们再想去拓展功能,只要接口不需要发生变化,我们就无需去动之前的代码,只需要增加新的代码即可,这也符合开放-封闭原则,如果我们想去修改一些功能代码,比如把李四开宝马修改为李四开奔驰,只需要在业务逻辑层更换参数即可,无需动其它模块的内容,显然极大降低了代码之间的耦合度。

在这里插入图片描述

使用依赖倒转原则后,我们再去拓展新的功能或者修改一些功能就无需去更改其它模块中的内容了。

具体代码如下:

#include<iostream>
#include<string>
using namespace std;

//抽象层
class Car
{
	string name;
public:
	virtual void run() = 0;
	Car(string _name):name(_name){}
	string getName()
	{
		return name;
	}
};

class Person
{
public:
	virtual void drive(Car& car) = 0;
};

//实现层
class Benz :public Car
{
public:
	Benz(string _name) :Car(_name) {}
	virtual void run()
	{
		cout << "奔驰正在奔跑" << endl;
	}
};

class BMW :public Car
{
public:
	BMW(string _name) :Car(_name) {}
	virtual void run()
	{
		cout << "宝马正在奔跑" << endl;
	}
};

class Zhang3 :public Person
{
public:
	virtual void drive(Car& car)
	{
		cout << "张三在开" << car.getName() << endl;
		car.run();
	}
};

class Li4 :public Person
{
public:
	virtual void drive(Car& car)
	{
		cout << "李四在开" << car.getName() << endl;
		car.run();
	}
};

//业务逻辑层
int main()
{
	Person* person = new Zhang3;
	Person* person2 = new Li4;
	Car* car1 = new Benz("奔驰");
	Car* car2 = new BMW("宝马");
	person->drive(*car1);
	person2->drive(*car2);
	return 0;
}

通过上述解释,我们清楚了里氏代换原则和依赖倒转原则对代码的作用,但是在代码中还有一个值得注意的地方,很显然,实现层依赖了抽象层,而在业务逻辑层,我们要注意要让父类(抽象类)指针指向子类对象,这样业务逻辑层才是依赖了抽象层,才符合依赖倒转原则。

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

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

相关文章

CMake常用指令

CMake常用指令一、前言二、基本指令2.1、ADD_DEFINITIONS2.&#xff12;、ADD_DEPENDENCIES2.3、ADD_TEST 与ENABLE_TESTING 指令。2.4、AUX_SOURCE_DIRECTORY2.5、CMAKE_MINIMUM_REQUIRED2.6、EXEC_PROGRAM2.7、FILE 指令2.8、INCLUDE 指令2.9、其他指令三、FIND_系列指令四、…

云计算 概念与技术

如果我倡导的计算机在未来得到使用&#xff0c;那么有一天&#xff0c;计算也可能像电话一样成为共用设施。计算机应用将成为一全新的、重要的产业的基础。 ——John McCarthy 云计算的概念 定义 Garther公司的定义 一种计算方式&#xff0c;能通过Internet技术将可扩展的和…

内核模块调试常用命令整理

一、 模块加载 1.1 最简单的一个驱动 static int __init my_driver_init( void ) {printk("init my_driver\n");return 0; }static void __exit my_driver_exit( void ) {printk("exit my_driver\n"); }module_init( my_driver_init ); module_exit( my_…

Xamarin.Forsm for Android 显示 PDF

背景 某些情况下&#xff0c;需要让用户阅读下发的文件&#xff0c;特别是红头文件&#xff0c;这些文件一般都是使用PDF格式下发&#xff0c;这种文件有很重要的一点就是不能更改。这时候就需要使用原文件进行展示。 Xamarin.Forms Android 中的 WebView 控件是不能直接显示的…

R统计绘图-NMDS、环境因子拟合(线性和非线性)、多元统计(adonis2和ANOSIM)及绘图(双因素自定义图例)

这个推文也在电脑里待了快一年了&#xff0c;拖延症患者&#xff0c;今天终于把它发出来了。NMDS分析过程已经R统计-PCA/PCoA/db-RDA/NMDS/CA/CCA/DCA等排序分析教程中写过了。最近又重新看了《Numerical Ecology with R》一书,巩固一下知识&#xff0c;正好重新整理了一下发出…

火山引擎推出一站式小程序监控方案

背景 小程序作为轻量级的应用发展迅速&#xff0c;国内已有多家小程序厂商相继推出。为了洞察用户真实体验及程序自身运行状况&#xff0c;监控已成为开发套件中必不可少的一环。随着业务愈来愈复杂&#xff0c;各厂商小程序管理后台免费提供的监控能力逐渐满足不了大部分业务…

软考中级之数据库系统(重点)

涉及考点:数据库模式,ER模型,关系代数与元祖演算,规范化理论,并发控制,分布式数据库系统,数据仓库和数据挖掘 数据库模式 三级模式-二级映射 常考选择题 三级模式,两种映射的这种涉及属于层次架构体的设计,这种设计为我们在应用数据库的时候提供了很多便利,同时提高了整个体…

功能性材料深入超级赛道,赋能多行业迭代升级

中国国际胶粘剂及密封剂展览会深耕胶粘剂、密封剂和胶粘带行业26年&#xff0c;是行业认可的、优质的贸易与技术交流平台。展会连接了十几个行业的买家和卖家&#xff0c;包括汽车、电子、新能源、轨道交通、工业等重要领域&#xff0c;为客户提供封装、粘合、散热、装配制造等…

拿下宁王、迪王的湖南裕能,还能“狂飙”多远?

文|智能相对论作者|Kinki近日&#xff0c;磷酸铁锂正极材料龙头湖南裕能正式登陆A股&#xff0c;上市当天市值超过了400亿元&#xff0c;投资者中一签可赚1.49万元&#xff0c;可谓近年低迷的资本市场中一支“大肉签”。不过在 “开门红”之后&#xff0c;湖南裕能的股价便一路…

leetcode16. 最接近的三数之和

给你一个长度为 n 的整数数组 nums 和 一个目标值 target。请你从 nums 中选出三个整数&#xff0c;使它们的和与 target 最接近。 返回这三个数的和。 假定每组输入只存在恰好一个解。 示例 1&#xff1a; 输入&#xff1a;nums [-1,2,1,-4], target 1 输出&#xff1a;2 …

linux服务器上Docker中安装jenkins

前言 Jenkins是开源CI&CD软件领导者&#xff0c; 提供超过1000个插件来支持构建、部署、自动化&#xff0c; 满足任何项目的需要。 本文主要提供通过docker安装jenkins镜像&#xff0c;并配置nginx反向代理页面配置和使用。通过jenkins完成项目的自动部署。 我在安装之前…

ThinkPHP ^6图片操作进阶

图片裁剪、缩略、水印不再是TP框架系统内置的功能&#xff0c;需要安装。 目录 安装 图片处理 1.创建图片对象 2.获取图片属性 3.裁剪图像 4.生成缩略图 6.保存图像 7.水印 安装 使用composer在项目根目录打开命令行执行&#xff1a; composer require topthink/think…

Simulink 电机控制:单电阻三相电流重构算法仿真总结

目录 理论基础 仿真实现 硬件实现 总结 理论基础 参考Microchip AN1299 《PMSM 无传感器 FOC的单分流三相电流重构算法》&#xff0c;详细的理论可以参考这个文档&#xff0c;这里只简单总结一下。单电阻采样的核心就是要在一个周期内实现两相电流的采样并通过基尔霍夫定…

【UE4 制作自己的载具】3-载具蓝图实现(基本)

效果步骤新建一个蓝图&#xff0c;继承“WheeledVehicle&#xff08;轮式载具&#xff09;”命名为“Vehicle_BP”&#xff0c;双击打开该蓝图选中“Mesh&#xff08;继承&#xff09;”&#xff0c;然后在细节中&#xff0c;骨架网格体选择“Vehicle”添加一个弹簧臂和摄像机组…

Windows下mysql8.0.32安装配置方法图文教程

Windows下mysql8.0.31安装配置方法图文教程 1、下载可以到官网的地址下载即可 https://dev.mysql.com/downloads/file/?id516465 2、解压缩并重命名mysql-8.0.32-winx64为mysql 3、创建my.ini配置文件&#xff0c;创建data文件夹。 4、打开记事本另存为my.ini并且使用ANSI编…

23年了,GOPATH和go.mod 还在冲突!

现在 新配了 go环境 设置了GOROOT&#xff0c;GOPATH &#xff0c;发现引用别的包会出问题。一直会报 package XX not in GOROOT &#xff08;xxxx&#xff09;我的目录&#xff1a;我的开发目录&#xff1a; /home/fate/go_projects/老样子&#xff0c;下面有 /home/fate/go_…

元宇宙与ChatGPT结合 一场颠覆式场景革命或将到来?

元宇宙和ChatGPT都是当前数字化领域中非常热门的技术和应用&#xff0c;两者之间也存在一定的关系&#xff0c;结合起来&#xff0c;可以为企业提供更加智能化、个性化的服务和支持&#xff0c;同时也可以拓展企业的市场和品牌影响力&#xff0c;提高企业的效率和创新能力。 元…

公司新来一00后说我不会自动化测试,3个问题直接给他问趴下...

今天我们公司刚入职一小伙&#xff0c;听说是00后&#xff0c;今天在办公室交流了一下&#xff0c;他问我会不会自动化测试&#xff0c;我直呼好家伙&#xff0c;直接问了他3个开展自动化测试问题....一问3不知.....还有待加强呀我们在制定自动化测试实施策略时&#xff0c;首先…

java servlet详解

一、Servlet实现方式 1、实现Servlet接口&#xff0c;接口中的方法必须全部实现。此种方式支持最大程度的自定义。 2、继承GenericServlet&#xff0c;service方法必须重写&#xff0c;其他方可根据需求&#xff0c;选择性重写。 使用此种方式&#xff0c;表示只在接收和响应…

作为通信人,你知道国内有哪些通信领域的博物馆吗?

众所周知&#xff0c;博物馆是收藏、展示和研究历史文物的地方。参观博物馆&#xff0c;既可以回顾历史往事&#xff0c;也可以学习知识。 那么&#xff0c;作为通信人&#xff0c;你知道国内有哪些通信领域的博物馆吗&#xff1f; 今天&#xff0c;就让小编给大家介绍介绍。█…