依赖倒转原则和里氏代换原则详解
初学依赖倒转原则和里氏代换原则时,由于笔者水平有限,并没有看懂书上的专业术语的解释,经过反复摸索和学习,发现里氏代换原则和依赖倒转原则可以一言以蔽之:
里氏代换原则:开发时以抽象为核心,针对抽象编程,能够抽象为一个抽象类或者接口的,就将其抽象为抽象类或者接口,然后用子类来进行实现
依赖倒转原则:将代码分为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;
}
通过上述解释,我们清楚了里氏代换原则和依赖倒转原则对代码的作用,但是在代码中还有一个值得注意的地方,很显然,实现层依赖了抽象层,而在业务逻辑层,我们要注意要让父类(抽象类)指针指向子类对象,这样业务逻辑层才是依赖了抽象层,才符合依赖倒转原则。
依赖倒转原则和里氏代换原则详解相关推荐
- 带你认识六种设计原则(开闭原则、里氏代换原则、依赖倒转原则....)
前言 1. 设计原则 1.1. 开-闭原则 1.2. 里氏代换原则 1.3. 依赖倒转原则 1.4. 接口隔离原则 1.5. 合成/聚合原则 1.6. 迪米特法则 前言 学习设计模式之前先要了解其中的 ...
- 设计原则 单一职责原则、开放封闭原则、依赖倒置原则、里氏代换原则、迪米特法则
目录 1 单一职责原则 2 开放封闭原则 3 依赖倒置原则 4 里氏代换原则 5 迪米特法则 1 单一职责原则 比如:电脑内存坏了就应该更换内存,不应该更换CPU (内存负责内存.CPU负责CPU) ...
- Java设计原则之单一职责原则、开闭原则、里氏代换原则
文章目录 面向对象设计原则概述 单一职责原则 开闭原则 里氏代换原则 面向对象设计原则概述 软件的可维护性(Maintainability)和可复用性(Reusability)是两个非常重要的用于衡量 ...
- 设计模式-设计原则之里氏代换原则
设计原则之里氏代换原则 里氏代换原则 案例(正方形不是长方形) 案例改进 里氏代换原则 里氏代换原则是面向对象设计的基本原则之一. 里氏代换原则:任何基类可以出现的地方,子类一定可以出现. 通俗理解: ...
- 面向对象——依赖倒转原则和里氏代换原则
什么是依赖倒转原则 下面三个就是 高层模块不依赖低层模块 抽象不依赖细节 细节依赖抽象 为什么需要这个原则? 假设现在需要开发一个软件,其中某个功能需要和数据库进行操作 那么,马上能想到的方法是不是就 ...
- 依赖倒转原则与里氏代换原则
看了一下书,还是慢慢感受到了面向对象编程的强大,依赖倒转原则的思想主要是:面向抽象(接口)编程,而不是针对细节编程.面向抽象编程的自己理解就是先将某个具体的事物先扩大,抽象成一类事物,先对这一类事物进 ...
- 【设计模式系列学习笔记】5、依赖倒转原则和里氏代换原则
依赖倒转原则:抽象不应该依赖细节,细节应该依赖于抽象: 针对接口编程,不要对实现编程: 高层模块不应该依赖底层模块,两个都应该依赖抽象: 抽象不应该依赖细节,细节应该依赖抽象: 里氏代换原则 一个软件 ...
- Java设计模式之设计的6大原则(开闭原则,里氏代换原则,依赖倒转原则,接口隔离原则,最少知道原则,合成复用原则)
1. 开闭原则 核心思想:一个对象对外扩展开发,对修改关闭 意思就是:对类的改动是通过增加代码进行的,而不是修改现有的代码. 也就是说软件开发人员一旦写出了可以运行的代码,就不应该去改动它,而是要保证 ...
- 大话设计模式三之单一职责原则、开放-封闭原则、依赖倒置原则、里氏代换原则
单一职责原则 单一职责原则(SRP),意思就是说,功能要单一.准确解释是,就一个类而言,应该仅有一个引起它变化的原因. 如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或 ...
最新文章
- R语言dataframe计算满足筛选条件的行的个数(筛选满足条件的数据行并计数):类似于excel的countif函数
- hadloop大数据平台论文_企业大数据平台建设过程中的问题和建议
- 中业科技机器人价格_2019年年中盘点:智能扫地机器人十大畅销品牌排名
- (持续更新)webstorm快捷键及术语翻译
- 严加安:想象力、直觉和灵感
- 一道关于String的易错习题
- SHELL常见的系统变量解析
- 统计学习三要素的思考
- ConcurrentHashMap1.7到1.8变化
- 专业音频测试软件应用比对,(精品文献)专业音频测试软件应用比对(升级版)_汤磊.pdf...
- coreldrawx4缩略图显示不出来_cdrx4无法显示缩略图怎么办?不显示缩略图解决方法...
- 微信小程序如何跳转视频号直播间
- 张小龙的话与微信的玄机
- webpack抽离 公共代码
- 4G 工业路由器并入cisco专网
- 小程序转uniapp——disabled
- PCB常见的几种钻孔
- MySQL - 用户管理
- YOLOX训练自己的VOC数据集
- net-java-php-python-医药库存管理系统计算机毕业设计程序