面向对象设计原则实践.之二.依赖倒转原则

(nginx) nginx5 nginx https部署实战 综上所述,相比 HTTP 协议,HTTPS 协议增加了很多握手、加密解密等流程,虽然过程很复杂,但其可以保证数据传输的安全。所以在这个互联网膨胀的时代,其中隐藏着各种看不见的危机,为了保证数据的安全,维护网络稳定,建议大家多多推广HTTPS。SSL 证书费用很高,以及其在服务器上的部署、更新维护非常繁琐HTTPS 降低用户访问速度(多次握手)网站改用HTTPS 以后,由HTTP 跳转到 HTTPS 的方式增加了用户访问耗时(多数网站采用302跳转) 阅读详情

二、依赖倒转原则(DIP--Dependency Inversion Principle)

1.依赖倒转原则定义

a). 高层模块不应该依赖低层模块,它们都应该依赖抽象。

抽象不应该依赖于细节,细节应该依赖于抽象。

b). 要针对接口类/抽象类编程,不要针对实现编程。 

 

高层模块包含了一个应该程序中的重要的策略选择和业务模型,

正是这些高层模块才使得其所有的应用程序区别于其他,

如果高层依赖于低层,那么对低层模块的改动就会直接影响到高层模块,从而迫使它们依次做出改动。 

 

2. 依赖倒转原则分析

a)  简单来说,依赖倒转原则就是指:

代码要依赖于抽象的类,而不要依赖于具体的类;

要针对接口或抽象类编程,而不是针对具体类编程。

b)  实现开闭原则的关键是抽象化,并且从抽象化导出具体化实现,

如果说开闭原则是面向对象设计的目标的话,那么依赖倒转原则就是面向对象设计的主要手段。

c) 依赖倒转原则的常用实现方式之一是:

在代码中使用抽象类,而将具体类放在配置文件中。

d) 类之间的耦合:

> 零耦合关系 : 无关系

> 具体耦合关系  : 强关系

> 抽象耦合关系。     : 弱关系

  依赖倒转原则要求客户端与实现类之间是 通过抽象类进行耦合。

以抽象耦合是依赖倒转原则的关键。

e)  依赖注入:

构造注入:通过构造函数注入实例变量

设值注入:通过Setter方法注入实例变量

接口注入:通过接口方法注入实例变量

 

3. 实例一

某系统提供一个数据转换模块,可以将来自不同数据源的数据转换成多种格式,如,

可以转换来自数据库的数据(DatabaseSource)、也可以转换来自文本文件的数据(TextSource),

转换后的格式可以是XML文件(XMLTransformer)、也可以是XLS文件(XLSTransformer)

依赖倒转原则-图-1

依赖倒转原则-图-2

图(一)和图(二)分析:

因为该系统可能需要增加新的数据源或者新的文件格式,

(图一)中,每增加一个新的类型的数据源或者新的类型的文件格式,

客户类MainClass都需要修改源代码,以便使用新的类,这违背了开闭原则。

(图二)使用依赖倒转原则对其进行重构:

a) 客户类MainClass 依赖于两个抽象类变量: AbstractSource, AbstractTransformer;

其中,抽象类AbstractSource的子类 DatatbaseSource , TextSource是不同输出入源的实现;

抽象类AbstractTransformer的子类XMLTransformer, XLSTransformer是不同输出格式的实现。

而客户类通过配置文件config.xml来确定到底如何处理数据;

 

 

4. 实例二

反面例子: 

缺点:耦合太紧密,Light发生变化将影响ToggleSwitch。 

 

解决办法一: 

将Light作成Abstract,然后具体类继承自Light。 

优点:ToggleSwitch依赖于抽象类Light,具有更高的稳定性,

而BulbLight与TubeLight继承自Light,可以根据"开放-封闭"原则进行扩展。

只要Light不发生变化,BulbLight与TubeLight的变化就不会波及ToggleSwitch。 

 

缺点:如果用ToggleSwitch控制一台电视就很困难了。

总不能让TV继承自Light吧。 

 

解决方法二: 

优点:更为通用、更为稳定。 

 

上面的计算器例子用这个原则更进一步的优化的代码如下:

#include <stdio.h>

#include <stdlib.h>

#include <iostream>

#include <string>



using namespace std;



/* Step1:

* 使用vitual定义函数的功能模块,相当于实现公共界面设计

*/

class IGetResult {

public:

//virtual double get_result(double numberA, double numberB) = 0;

virtual double get_result() = 0;



public:

/* 注意一定要不要忘记添加虚析构函数 */

virtual ~IGetResult(){}

};



/* Step2 :

* 继承基类,定义具体的功能模块,并声明具体需要的私有成员变量

* 实现具体的功能模块

*/

class Add : public IGetResult {

public:

Add(double a, double b){

std::cout << "Add" << endl;



m_numberA = a;

m_numberB = b;

};



~Add(void) {};



public:

double get_result();

private:

double m_numberA;

double m_numberB;

};



/* 实现具体的功能模块 */

double Add::get_result() {

std::cout << "Add::get_result()" << endl;



return m_numberA + m_numberB;

}



class Del : public IGetResult {

public:

Del(double a, double b){

std::cout << "Del" << endl;

m_numberA = a;

m_numberB = b;

};



virtual ~Del(void) {};



public:

double get_result();



private:

double m_numberA;

double m_numberB;

};



double Del::get_result(){

std::cout << "Del::get_result()" << endl;



return m_numberA - m_numberB;

}



class Mul: public IGetResult {

public:

Mul(double a, double b){

std::cout << "Mul" << endl;

m_numberA = a;

m_numberB = b;

};

virtual ~Mul(void) {};

public:

double get_result();

private:

double m_numberA;

double m_numberB;

};

double Mul::get_result(){

std::cout << "Mul::get_result()" << endl;



return m_numberA * m_numberB;

}



/* Step4:

* 将功能函数接口注入封装类中

*/

class MainOperate {

public:

MainOperate(IGetResult *get_result_ptr){

this->m_get_result = get_result_ptr;

}

public:

double Operate();

private:

IGetResult *m_get_result;

};



/* 实现封装类中的接口函数的具体调用方式 */

double MainOperate::Operate(){

double ret = 0;

ret = this->m_get_result->get_result();

return ret;

}







int main(int argc, char* argv[]){

std::cout << "main()" << endl;

int a = 22;

int b = 10;

int ret = 0;

/* Step5: 主函数中定义调用模块接口函数*/

IGetResult *get_result = new Add(a, b);



/* Step6: 主函数调用封装类中接口函数*/

MainOperate *main_operate = new MainOperate(get_result);

ret = main_operate->Operate();

std::cout << "ret = " << ret << endl;

delete get_result;



get_result = new Del(a, b);

main_operate = new MainOperate(get_result);

ret = main_operate->Operate();

std::cout << "ret = " << ret << endl;

delete get_result;

get_result = new Mul(a, b);

main_operate = new MainOperate(get_result);

ret = main_operate->Operate();

std::cout << "ret = " << ret << endl;

delete get_result;



/*

Add add = Add(a, b);

ret = add.get_result();

std::cout << "ret = " << ret << endl;



Del del = Del(a, b);

ret = del.get_result();

std::cout << "ret = " << ret << endl;

*/

return 0;

}

特点:

代码要依赖于抽象的类,而不要依赖于具体的类;

针对接口或抽象类编程,而不是针对具体类编程。

实现了接口注入;

 

 

5. 总结

高层模块不应该依赖底层模块,两个都应该依赖与抽象;

抽象不应该依赖于细节,细节应该依赖于抽象。

客户端与实现类通过抽象类进行耦合。

 

DIP优点: 

使用传统过程化程序设计所创建的依赖关系,策略依赖于细节,这是糟糕的,因为策略受到细节改变的影响。

依赖倒置原则使细节和策略都依赖于抽象,抽象的稳定性决定了系统的稳定性。 

 

DIP注意点:

1)、任何变量都不应该持有一个指向具体类的指针或者引用 

2)、任何类都不应该从具体类派生(始于抽象,来自具体) 

3)、任何方法都不应该覆写它的任何基类中的已经实现了的方法 

PostgreSQL核心原理:数据库崩溃恢复的唯一真相详解 PostgreSQL崩溃恢复机制通过WAL日志确保数据一致性和持久性。核心流程包括:触发恢复(非正常关闭时)、读取控制文件获取检查点LSN、顺序扫描WAL日志进行Redo阶段重做已提交事务、利用MVCC标记未提交事务为ABORTED实现逻辑撤销,最后执行检查点完成恢复。该机制依赖WAL原子性、检查点锚点和无Undo的可见性模型三大支柱,保证即使系统崩溃也能恢复到逻辑一致状态。关键设计包括延迟写入、LSN顺序控制和FPW防部分写,最终通过确定性重放实现ACID特性。 阅读详情

相关推荐

高速电路的信号完整性分析

摘要:介绍了高速PCB设计中的信号完整性概念以及破坏信号完整性的原因,从理论和计算的层面上分析了高速电路设计中反射和串扰的形成原因,并介绍了IBIS仿真。 关键词:信号完整性 反射 串扰 IBIS仿真 随着半导体技术和深压微米工艺的不断发展,IC的开关速度目前已经从几十MHz增加到几百MHz,甚至达到几GHz。在高速PCB设计中,工程师经常会碰到误触发、阻尼振荡、过冲、欠冲、串...

bh_wang的专栏 1431

面向对象设计原则-依赖倒置原则

依赖倒置原则的定义 高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象。其核心思想是:要面向接口编程,不要面向现实编程。 依赖倒置原则是实现开闭原则的重要途径之一,他降低了客户与实现之间的耦合。 由于在软件设计中,细节具有多变性,而抽象层相对稳定,因此以抽象为基础搭建起来的架构要比以细节为基础搭建起来的架构要稳定的多。这里的抽象指的是接口或者是抽象类,而细节是指具体的实现类。 使用接口或者抽象类的目的是规定好规范和契约,而不去设计任何具体的操作,把展现细节的任务交

xue_wu_zhi_jing1的博客 863

【FOC无刷电机控制】六步换向、FOC,STM32cubemx从零开始搭建BLDC六步换相代码、FOC代码(基于霍尔传感器)

FOC、六步换相,无刷电机控制

xifan的博客 3万+

面向对象五大设计原则-依赖倒置原则

1、什么是依赖倒置原则 高层模块不应该依赖于低层模块,两者都应该依赖于抽象; 抽象不应该依赖于细节; 细节应该依赖于抽象; 2、高层依赖于底层示例 山寨手机的主板制造依赖于具体的某摄像头型号、收音机模块、播放器模块、点火模块、投影仪模块; 类似这样从上向下的依赖关系是非常脆弱的,因为任何底层模块发生变化,都将从下而上的影响整个产品链。 3、依赖倒置示例 在山寨手机出现了问题后,专业手机生产制造商们,和基础元件的供应商一起举行了移动平台高峰论坛,共同制定了手机行业的统一标准接口。

u014354882的博客 664

Procedural modeling

What is procedural modeling? One content generation option is modeling buildings, plants, clouds, cities, and worlds using an underlying system of rules. 1 Procedural Modeling: Grammars A rule-based generative system loosely organized as: ...

qq_24505417的博客 711

CentOS 7环境下GLPI与OCS Inventory资产管理系统集成部署指南

本文详细介绍了在CentOS 7环境下,如何将GLPI与OCS Inventory两大开源工具进行集成部署,构建自动化资产管理系统。指南涵盖环境准备、核心服务安装、Web界面初始化、OCS插件配置及资产同步实战,帮助运维人员实现IT资产的自动发现、统一管理与可视化,大幅提升资产管理效率。

weixin_29274337的博客 327

设计模式概念和七大原则

设计模式概念和七大原则 转载 设计模式概念和七大原则 什么是设计模式 在GoF(Gang of Four)的书籍《Design Patterns - Elements of Reusable Object-Oriented Software(设计模式-可复用面向对象软件的基础)》中是这样定义设计模式的:Christopher Alexander说过:“每一个模式描述了一个在我们周围不断重复发生的问题以及该问题的解决方案的核心。这样,你就能一次又一次地使用该方案而不必做重复劳动” [AIS+77,第10页

sinat_37316828的博客 316

手把手教你学基带SOC芯片(4.2)--基带soc芯片的存储器设计

基带 SoC 中的存储器设计需要综合考虑功耗、成本和性能等因素。SRAM 适合高速缓存,DRAM 适合主内存,Flash 存储器适合非易失性存储。通过优化存储单元设计、阵列布局和外围电路,可以提高存储器的性能和效率。

MHD0815的博客 350

4.依赖倒置原则

文章目录一、定义二、常见的系统模块设计三、依赖导致原则分析四、依赖倒置原则修改系统结构五、依赖注入1.依赖注入的方式(1)构造注入(2)设值注入(3)接口注入六、依赖倒置原则实例1、存在问题2、依赖倒置原则重构 一、定义   (1)高层模块不应该依赖低层模块,它们都应该依赖抽象;抽象不应该依赖于细节,细节应该依赖于抽象。无论是高层模块还是低层模块,都应该依赖于抽象。   另外一种表述:要针对接口编程,不要针对实现编程。实现指的是具体的类,是不稳定的。   (2)结构良好的面向对象架构都具有清晰的层次定义,每

qq_43403759的博客 1420

Python爬虫教程:抓取电商网站评论(以淘宝和京东为例)

通过本文的介绍,我们学会了如何使用Python编写爬虫,抓取淘宝和京东等电商平台的商品评论数据。我们介绍了如何使用电商平台提供的开放API以及如何通过模拟浏览器来抓取动态加载的数据。此外,我们还讨论了如何应对反爬虫技术,如何存储抓取的数据等。爬取电商平台的数据是一个强大的工具,能够为市场分析、消费者行为研究、产品优化等领域提供有力的支持。然而,在使用爬虫技术时,我们必须遵循法律法规,尊重平台的隐私政策,避免滥用数据。

2201_76125261的博客 1738

芒果YOLOv12改进13:独家原创改进最新 CFNet 核心结构|即插即用 | 首发改进显著提升检测性能,小目标检测涨点必备

芒果YOLOv12改进13:独家原创改进最新 CFNet 核心结构|即插即用 | 首发改进显著提升检测性能,小目标检测涨点必备

包括YOLOv5、YOLOv7、YOLOv8等模型改进 289

面向对象设计原则之依赖倒转原则

一、定义 依赖倒转原则(Dependence Inversion Principle, DIP)的定义:高层模块不应该依赖于低层模块,它们都应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。 另一种表述:要针对接口编程,不要针对实现编程。 对各种概念进行一个描述: 低层模块:不可分割的原子逻辑,可能会根据业务逻辑经常变化。 高层模块:低层模块的再组合,对低层模块的抽象。 抽象:...

weixin_40216444的博客 560

【图像去噪】基础知识之加噪 | 给图像加噪的若干种方式,包括加高斯白噪声(AWGN)、泊松-高斯噪声、模拟真实噪声(SIDD、DND)等

本文介绍给干净图像加噪的若干种方式,新手入门必看!。根据noise类型不同,产生不同的Noisy,Noisy一般是模型输入。【图像去噪】基础知识之图像流 | 图像从输入到输出的前世今生,包括类型变化、维度变化、数值变化等。

主要更新底层视觉(去噪、超分等)相关的科研内容,形式为【论文精读】+【论文复现】 1100

1、面向对象的设计原则

设计模式有24个(23 +1),设计模式的作用就是为了在一定环境下,用固定的套路解决问题设计模式的核心思想:不是消灭变化,而是把变化都驱赶到一个地方创建型(Creational)模式:如何创建对象结构型(Structral)模式:如何实现类或者对象的组合行为型(Behavioral)模式:类或对象怎么交换以及分配职责。

如月之恒,如日之升 442

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

E3、面向对象设计原则实训

在面向对象的设计里面,可维护性复用都是以面向对象设计原则为基础的,这些设计原则首先都是复用的原则,遵循这些设计原则可以有效地提高系统的复用性,同时提高系统的可维护性。设计原则的应用:在实验中,我尝试将依赖倒转原则和合成复用原则应用到画笔类的重构中。这个过程让我认识到了设计原则在解决实际问题中的应用价值,也让我意识到了在设计初期就考虑这些原则的重要性。继承与组合的选择:在分析正方形和长方形的关系时,我重新思考了继承和组合的使用场景。开闭原则的重要性:在图形库API的重构中,我体会到了开闭原则的核心价值。

m0_74161592的博客 867

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

设计模式之六大原则

在我们学习的23种模式中,每个模式都是按照设计模式的六大原则而设计的,只不过是每种模式体现的原 则的侧重点不同,下面我们来介绍一下这六大原则 一、分述 1.单一职责原则 对于一个类,应该仅有一个引起它变化的原因;当发生引起一个类变化的原因有很多的时候,那么这 个类就会与其他类的耦合性增强,这样对于系统的维护是很不利的,也不符合设计软件低耦合的思想 单例模式是能很好

狂奔的蜗牛 1573

OOP面向对象编程的几大原则

部分转载,部分原创。 1. 开闭原则(Open Close Principle) 开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。  2. 里氏代换原则(Liskov Substitution

学而不思则罔 思而不学则殆 1515

面向对象设计原则

面向对象设计原则 一、单一职责原则 定义:一个对象应该只包含单一的职责,并且该职责被完整的封装在一个类中。(就一个类而言,应该仅有一个引起它变化的原因) 解释:在软件系统中,一个类(大到模块,小到方法)承担的职责越多,它被复用的可能性就越小,而且一个类承担的职责过多,相当于将这些职责耦合在一起,当其中一个职责变化时可能会影响其它职责的运作,因此要将这些职责进行分离,将不同的职责封装在不同的类中,即不同的变化原因封装在不同的类中,如果多个职责总是同时发生改变则可以将它们封装在同一个类中。单一职责原则是实现高.

m0_50328761的博客 146

跟我一起学“仓颉”设计模式-面向对象设计原则

本章为大家详细的介绍了仓颉设计模式中面向对象设计原则的内容。

Cool_foolisher的博客 581

Java设计模式的七大设计原则

定义:即一个类应该只负责一项职责。它规定一个类应该只有一个发生变化的原因,所谓职责是指类变化的原因。如果一个类有多于一个的动机被改变,那么这个类就具有多于一个的职责。在业务中,最常见的的就是对数据表的操作,每个表都有自己的Service层。假设有一个用户表和角色表,那么就分别存在UserService和RoleService两个类,每个类只对自己的表做操作。但有些业务场景会需要对两张表做关联查询、修改等操作,那么理应当再新增一个类专门用于处理这两张表的关联操作才符合单一职责原则。 意义:定义:即一个类对另一

LyrZn的博客 128

面向对象设计的六大原则

前言 面向对象的三大特性:封装、继承、多态 面向对象的四大好处:可维护、可扩展、可复用、灵活性好 面向对象的六大基本原则是设计模式的基础 一、单一职责原则 1、概念:一个类,应该仅有一个引起它变化的原因。 2、描述:如果一个类承担的职责过多,就等于把这些职责耦合在一起,一个职责的变化可能会削弱或抑制这个类完成其它职责的能力。这种耦合会导致脆弱的设计,当变化发生时,设计会受到意想

山野村夫pro的专栏 428

面向对象编程原则(10)——总结

在软件开发中使用面向对象设计原则可以提高软件的可维护性和可复用性,以便设计出兼具良好的可维护性和可复用性的软件系统,实现可维护性复用的目标。

谷哥的小弟 387

Java与模式

Java与模式本人接下来要学习Java与模式一书(阎宏编著)在学习过程中记下自己学习的一些心得和体会,希望和大家一起学习共同探讨与讨论。呵呵,这句话挺有味道的,和大家一起分享下:在西方的思想里面,分析一个结构直到把它分解为不可分割的单位,再加以数量化的研究和描述,是其典型的数理分析的套路。在西方科学文化中,不能够精确化和数量化的结构不受重视。而在中国传统的文化里面,不能够精确化和数量化

liyangbing315的专栏 655

设计模式初步接触

什么是设计模式,为什么要使用设计模式,设计模式7大基本原则

九尾小白的博客 284

(转)oop设计模式简介

每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心。-- Christopher Alexander   设计模式描述了软件设计过程中某一类常见问题的一般性的解决方案。面向对象设计模式描述了面向对象设计过程中、特定场景下、类与相互通信的对象之间常见的组织关系。   设计模式与面向对象   面向对象设计模式解决的是“类与相互通信的对象之间的组织关系,...

weixin_30639719的博客 84

面向对象设计模式——六大设计原则

面向对象六大设计原则 单一职责原则、依赖倒转原则、米特莱迪法则、依赖倒转原则、开闭原则、依赖倒转原则 单一职责 Single Responsibility Principle 一个类只有一个发生变化的原因 具体到函数的功能,类的功能,接口的功能 开闭原则 Open Closed Principle 一个软件实体,如类,模块和函数,应该对扩展开发,对修改关闭 里式替换原则 Liskov Substitution Principle 所引用基类的地方必须能透明的使用其子类的对象 米特莱迪法则 Law of De

qq_42766309的博客 213

设计模式:设计模式的相关概念与原则

前面我们已经利用过一些设计模式来写过小项目,但是那个时候我们对于设计模式还不了解,本期我们来深入讲解设计模式相关的知识。

2401_89119815的博客 664
上一篇: 面向对象设计原则实践:之一.开放封闭原则
下一篇: 面向对象设计原则实践:之三.单一职责原则,合成复用原则
北雨南萍
北雨南萍 领域专家: 操作系统技术领域 领域专家: 操作系统技术领域
博客等级 码龄20年 2665粉丝 453原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

北雨南萍

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值