设计模式-03 设计模式-依赖倒转原则案例分析


设计模式-03 设计模式-依赖倒转原则案例分析

目录

设计模式-02 设计模式-依赖倒转原则案例分析

1.定义

2.内涵

3.案例对比

4.注意事项

5.最佳实践

6.总结


1.定义

依赖倒转原则(Dependency Inversion Principle,简称DIP)高层级的模块不能依赖底层级模块的,两种层级的模块应该依赖抽象,抽象层不能依赖具体实现层,具体实现应该依赖抽象

通俗来说,DIP 意味着:

客户端代码(高层模块)不应该直接依赖于具体实现(低层模块)。
相反,客户端代码应该依赖于一个抽象,而抽象再依赖于具体实现。


                   +--------------+
                   |  客户端代码  |
                   +--------------+
                         |
                         V
                   +--------------+
                   |    抽象类    |
                   +--------------+
                         |
                         V
                   +--------------+
                   | 具体实现类 |
                   +--------------+

说明:

  • 客户端代码(高层模块)依赖于抽象类,而不是具体的实现类。
  • 抽象类定义了客户端代码所需的行为,而具体实现类提供了这些行为的具体实现。
  • 客户端代码通过依赖注入接收其依赖项(抽象类)。
  • 通过使用 DIP,客户端代码与具体实现类之间的耦合最小化,从而提高了代码的灵活性、可测试性和可维护性。

                   

2.内涵

DIP 的定义出发点是:

软件的灵活性:当依赖关系是固定的时,很难在不影响其他模块的情况下修改软件。
软件的可测试性:当客户端代码直接依赖于具体实现时,很难对客户端代码进行单元测试。

3.案例对比

错误的设计,经常是依赖与具体的实现。而不是依赖与接口层。以下就具体案例进行的举例说明。


bad 设计

#include <iostream>
#include <cstdio>
#include <vector>
#include <fstream>
#include <tuple>
#include <string>

using namespace std;

enum class Relationship{
    parent,
    child,
    sibling,
};

struct Person{
    string name;
};

struct Relationships  // 底层模块
{
    vector<tuple<Person, Relationship, Person>> relations;

    void add_parent_add_child(const Person& parent, const Person& child){
        relations.push_back({parent, Relationship::parent, child});
        relations.push_back({child, Relationship::child, parent});
    }

};

struct Research  // 上层模块,依赖与底层的具体实现,而不是抽象接口,违反了依赖倒转原则
{
    Research(Relationships& relationships){
        auto& relations = relationships.relations;
        for(auto& [first, rel, second]: relations){
            if(first.name == "Hohn"  && rel == Relationship::parent){
                cout<<"Hohn has child :"<< second.name<< endl;
            }
        }
    }
};

int main() {
    Person parent{"Hohn"};
    Person child1{"Dhris"},child2{"Watt"};
    Relationships relationships;
    relationships.add_parent_add_child(parent,child1);
    relationships.add_parent_add_child(parent,child2);
    Research _(relationships);
    return 0;
}

好的设计

#include <iostream>
#include <cstdio>
#include <vector>
#include <fstream>
#include <tuple>
#include <string>

using namespace std;

enum class Relationship{
    parent,
    child,
    sibling,
};

struct Person{
    string name;
};

struct RelationshipBrowser{
    virtual vector<Person> find_all_children_of(const string& name) = 0;
};

struct Relationships :RelationshipBrowser // 底层模块
{
    vector<tuple<Person, Relationship, Person>> relations;

    void add_parent_add_child(const Person& parent, const Person& child){
        relations.push_back({parent, Relationship::parent, child});
        relations.push_back({child, Relationship::child, parent});
    }

    vector<Person> find_all_children_of(const string &name) override {
        vector<Person> result;
        for(auto&& [first,rel,second] : relations) {
            if(first.name == name && rel == Relationship::parent){
                result.push_back(second);
            }
        }
        return result;
    }


};


struct Research  // 上层模块不在依赖 Relationships ,而是依赖接口:RelationshipBrowser
{

    Research(RelationshipBrowser& browser){
        for(auto& child: browser.find_all_children_of("Hohn")){
            cout<<"Honh has child:"<< child.name<<endl;
        }
    }
//    Research(Relationships& relationships){
//        auto& relations = relationships.relations;
//        for(auto& [first, rel, second]: relations){
//            if(first.name == "Hohn"  && rel == Relationship::parent){
//                cout<<"Hohn has child :"<< second.name<< endl;
//            }
//        }
//    }
};

int main() {
    Person parent{"Hohn"};
    Person child1{"Dhris"},child2{"Watt"};
    Relationships relationships;
    relationships.add_parent_add_child(parent,child1);
    relationships.add_parent_add_child(parent,child2);
    Research _(relationships);
    return 0;
}

两种设计思路输出结果一样,但是好的设计遵循了依赖倒转原则,代码更灵活

Honh has child:Dhris
Honh has child:Watt
4.注意事项


在具体开发中,应用依赖倒转原则(DIP)时需要注意以下几点:

  • 明确接口和实现之间的关系:确保接口定义了客户端代码所需的行为,而实现提供了这些行为的具体实现。
  • 使用抽象类或接口来定义抽象:避免使用具体类作为抽象,因为这会违反 DIP。
  • 通过依赖注入传递依赖项:使用依赖注入框架或手动将依赖项传递给客户端代码,而不是让客户端代码直接创建依赖项。
  • 避免循环依赖:确保依赖关系是单向的,即高层模块不依赖于低层模块,低层模块也不依赖于高层模块。
  • 考虑性能影响:在某些情况下,使用 DIP 可能会有轻微的性能开销,因此在应用 DIP 时需要权衡利弊。

5.最佳实践

DIP 有以下优点:

  • 提高代码的灵活性:通过使用抽象,我们可以轻松地更改具体实现,而无需修改客户端代码。
  • 提高代码的可测试性:通过使用抽象,我们可以对客户端代码进行单元测试,而无需依赖于具体实现。
  • 减少耦合:DIP 减少了客户端代码与具体实现之间的耦合,从而提高了代码的可维护性和可重用性。

6.总结

DIP 并不是万能的,在某些情况下可能会有一些局限性:
(1)轻微的性能开销:使用 DIP 可能会有轻微的性能开销,因为需要额外的开销来管理依赖项。
(2)过度抽象:过度抽象可能会使代码难以理解和维护。

过度抽象就会使得系统复杂化,不便于后续优化。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

手撕spring框架(3)

手撕spring框架&#xff08;3&#xff09; 相关系列 手撕spring框架&#xff08;1&#xff09; 手撕spring框架&#xff08;2&#xff09; InitializingBean 接口详解 什么是 InitializingBean 接口&#xff1f; InitializingBean 接口是 Spring 框架中的一个接口&#xff0c…

【linux】进程(深入理解linux进程状态)

开始之前先说一个与本文无关的小知识&#xff0c;chdir命令可以更改当前进程的工作目录哦。 目录 linux具体进程状态&#xff1a;R && S&#xff1a;T && t&#xff1a;D&#xff1a;僵尸进程 && 孤儿进程&#xff1a; OS的理论线&#xff1a;运行&…

模型训练中的过拟合和欠拟合

基本概念 我们知道&#xff0c;所谓的神经网络其实就是一个复杂的非线性函数&#xff0c;网络越深&#xff0c;这个函数就越复杂&#xff0c;相应的表达能力也就越强&#xff0c;神经网络的训练则是一个拟合的过程。   当模型的复杂度小于真实数据的复杂度&#xff0c;模型表…

正版Office-Word使用时却提示无网络连接请检查你的网络设置 然后重试

这是购买电脑时自带的已经安装好的word。看纸箱外壳有office标记&#xff0c;但是好像没有印系列号。 某天要使用。提示&#xff1a;无网络连接请检查你的网络设置。 经过网上高手的提示&#xff1a; 说要勾选勾选ssl3.0、TLS1.0、1.1、1.2。 我的截图 我电脑进去就缺1.2. …

2024五一数学建模A题思路代码与论文分析

2024五一数学建模A题完整代码和成品论文获取↓↓↓↓↓ https://www.yuque.com/u42168770/qv6z0d/gyoz9ou5upvkv6nx?singleDoc# 2024五一数学建模A题钢板最优切割路径问题需要建立的模型和算法: 图论 最短路径算法(Dijkstra算法、Floyd算法等) 动态规划 网格化离散建模 …

Surya:强大的开源 OCR 文字识别工具

在当今数字化时代&#xff0c;文字识别技术扮演着至关重要的角色。VikParuchuri/surya 便是一款令人瞩目的开源 OCR 文字识别工具。 主要功能&#xff1a; 支持 90 多种语言的文字识别&#xff1a;Surya 具备强大的语言兼容性&#xff0c;能够轻松应对多种语言的文字识别任务&…

保存钉钉群直播回放下载:直播回放下载步骤详解

今天&#xff0c;我们就来拨开云雾&#xff0c;揭开保存钉钉群直播回放的神秘面纱。教会你们如何下载钉钉群直播回放 首先用到的工具我全部打包好了&#xff0c;有需要的自己下载一下 钉钉群直播回放工具下载&#xff1a;https://pan.baidu.com/s/1WVMNGoKcTwR_NDpvFP2O2A?p…

基于EBAZ4205矿板的图像处理:03摄像头采集HDMI输出视频图像

基于EBAZ4205矿板的图像处理&#xff1a;03摄像头采集HDMI输出视频图像 先看效果 项目简介 我是使用的EBAZ4205矿板&#xff0c;超级大电工的转接板和我自己买的一块没有xclk的ov5640完成的该项目&#xff0c;没有设备需自备。我就是跑通了正点原子的开源代码&#xff08;下文…

1991-2022年上市公司短贷长投/短债长用/投融资期限错配(包含原始数据及Stata代码)

01、数据简介 上市公司在投融资过程中&#xff0c;可能会涉及到投融资期限错配、短债长用和短贷长投等问题 投融资期限错配是指企业的资产与债务期限不匹配&#xff0c;主要表现为“短存长贷”&#xff0c;即资金来源短期化、资金运用长期化。当风险缓释的期限比当前的风险暴…

Elasticsearch:理解近似最近邻 (ANN) 算法

作者&#xff1a;来自 Elastic Elastic Platform Team 如果你是在互联网出现之前长大的&#xff0c;你会记得找到新喜好并不总是那么容易。我们是在无意中听到收音机里的新乐队时发现他们的&#xff0c;是因为忘了换频道偶然看到一个新电视节目的&#xff0c;也是几乎完全依据游…

本地搭建llama大模型及对话UI

环境说明&#xff1a;MBP 2023 M2Pro芯片 用到的工具/组件/技术&#xff1a;ollama、llama3:8b、docker、open-webui 1.下载ollama ollama官网下载地址&#xff1a;https://ollama.com/download 到ollama官网地址下载对应操作系统版本的ollama平台&#xff0c;按照安装指引…

unity制作app(2)--主界面

1.先跳转过来&#xff0c;做一个空壳&#xff01;新增场景main为4号场景&#xff01; 2.登录成功跳转到四号场景&#xff01; 2.在main场景中新建canvas&#xff0c;不同的状态计划用不同的panel来设计&#xff01; 增加canvas和底图image 3.突然输不出来中文了&#xff0c;浪…

区块链 | IPFS:CID

&#x1f98a;原文&#xff1a;Anatomy of a CID &#x1f98a;写在前面&#xff1a;本文属于搬运博客&#xff0c;自己留存学习。 1 CID 在分布式网络中与其他节点交换数据时&#xff0c;我们依赖于内容寻址&#xff08;而不是中心化网络的位置寻址&#xff09;来安全地定位…

stm32单片机开发四、USART

串口的空闲状态时高电平&#xff0c;起始位是低电平&#xff0c;来打破空闲状态的高电平 必须要有停止位&#xff0c;停止位一般为一位高电平 串口常说的数据为8N1&#xff0c;其实就是8个数据位&#xff08;固定的&#xff09;&#xff0c;N就是none&#xff0c;也就是0个校验…

审计师能力与专长数据集(2014-2022年)

01、数据介绍 审计师是专门从事审计工作的人员&#xff0c;他们对企业、政府机关、金融机构等组织进行独立的、客观的、合法的审计&#xff0c;以评估这些组织的财务状况、经营绩效和风险水平。审计师通过收集和评估证据&#xff0c;以确定被审计单位的财务报表是否公允、合法…

[数据结构]———交换排序

目录 1.交换排序 第一个定义了一个名为Swap的函数 第二个三数取中 2.冒泡排序 代码解析 冒泡排序的特性总结&#xff1a; 3.快速排序 1. hoare版本 2. 挖坑法 代码解析 3. 前后指针版本 代码解析 1.交换排序 基本思想&#xff1a;所谓交换&#xff0c;就是根据序列中两…

MyBatis-plus笔记——条件构造器和常用接口

wapper介绍 Wapper&#xff1a;条件构造抽象类 AbstractWapper&#xff1a;用于查询条件封装&#xff0c;生成 sql 的 where 条件 QueryWrapper&#xff1a;查询条件封装UpdateWrapper&#xff1a;Update 条件封装AbstractLambdaWrapper&#xff1a;使用Lambda语法 LambdaQuery…

五一假期Llama 3之魔改不完全攻略(Part 2)

2024年4月18日&#xff0c;Meta AI 正式宣布推出 Llama 3&#xff0c;这标志着开源大型语言模型&#xff08;LLM&#xff09;领域的又一重大进步。如同一颗重磅炸弹&#xff0c; Llama 3 以其卓越的性能和广泛的应用前景&#xff0c;预示着 AI 技术的新时代。 目前开源的是Lla…

Agent AI智能体:机器学习与自我优化的奇妙之旅

文章目录 &#x1f4d1;前言一、Agent AI智能体的基本概念二、Agent AI智能体的技术进步2.1 机器学习技术2.2 自适应技术2.3 分布式计算与云计算 三、Agent AI智能体的知识积累3.1 知识图谱3.2 迁移学习 四、Agent AI智能体的挑战与机遇4.1 挑战4.2 机遇 小结 &#x1f4d1;前言…

ASP.NET网络商店设计与实现

摘 要 本文首先系统地研究了开发电子商务网站的背景和意义&#xff0c;分析了当今B2C电子商务交易的网站特点和共性&#xff0c;从而得出设计本网站的思路和方法。接着介绍了实现系统开发的ASP.NET和IIS5.0环境&#xff0c;数据库用ACCESS实现。同时简要介绍了以上工具的功能…
最新文章