项目开发-依赖倒置、里式替换、接口隔离的应用深入理解

文章目录

  • 前言
  • 依赖倒置
    • 定义
    • 不符合依赖倒置原则是什么样子
    • 😄完善
  • 里式替换
    • 定义
    • 具体应用
  • 接口隔离
    • 定义
    • 具体应用

前言

最近在做.net项目和学习这个设计模式中的依赖倒置和工厂方法,这个过程当中发现在开发这个.net项目中有很多不合理的地方,就是我们使用了接口,但是在前端开发的时候还是使用的new的方式去给接口实例化,这还是违背了依赖倒置的原则。因为项目中并没有使用spring这些相关的框架,只是一个简单的三层模式UBD,之前在java项目中因为直接使用了spring的框架而忽略了在这个问题。
这里声明一下本次的代码示例均为Java语言。.net实现思路和这个一模一样。

依赖倒置

定义

依赖倒置原则(Dependency Inversion Principle)是面向对象设计中的一个原则,它是SOLID原则中的一部分,由罗伯特·C·马丁(Robert C. Martin)提出。该原则强调了高层模块不应该依赖于低层模块的具体实现细节,而应该依赖于抽象接口。具体来说,依赖倒置原则有以下几个核心概念:

  1. 模块间的依赖关系应该通过抽象发生,而不是具体实现发生。这意味着高层模块和低层模块都应该依赖于抽象接口或抽象类,而不是具体的实现类。

  2. 抽象不应该依赖于具体实现。抽象接口应该定义在高层模块中,并且不应该受到具体实现类的影响。这样可以保持高层模块的稳定性和独立性。

  3. 具体实现应该依赖于抽象。具体实现类应该依赖于抽象接口或抽象类,通过实现抽象定义的方法来完成具体的功能。

通过遵循依赖倒置原则,可以提高系统的可维护性、扩展性和灵活性。它可以降低模块间的耦合度,使得系统更容易进行修改和测试。另外,依赖倒置原则也促进了面向接口编程(Interface-Oriented Programming)的实践,强调了定义良好的抽象接口和合理的接口设计。

需要注意的是,依赖倒置原则并不是要求完全避免依赖关系,而是通过合理的抽象和接口设计来管理和控制依赖关系,以提高系统的灵活性和可维护性。

不符合依赖倒置原则是什么样子


import com.example.onlystudent.DIPDemo.Dao.ItemDao;
import com.example.onlystudent.DIPDemo.Dao.ItemDao4MysqlImpl;

//B层实现类。
public class ItemManagerImpl {
    //作为B层,这里是直接依赖的D层的代码,可以看到使用的是D层的接口。
    // 但是还是在给接口实例化的时候使用到了具体的实现来,并且在这个B层的import中出现了实现类的相关信息。
    ItemDao itemDao=new ItemDao4MysqlImpl();
}

package com.example.onlystudent.DIPDemo.Dao;

//D层接口
public interface ItemDao {
	//仅做demo展示,并为声明任何方法 
}
package com.example.onlystudent.DIPDemo.Dao;

//D层接口的实现类,这里是一个MySQL语法的实现类
public class ItemDao4MysqlImpl implements ItemDao {
    	//仅做demo展示,并为声明任何方法 
}
package com.example.onlystudent.DIPDemo.Dao;
//D层接口的实现类,这里是一个Oracle语法的实现类
public class ItemDao4OracleImpl implements ItemDao{
	//仅做demo展示,并为声明任何方法 
}

在这套代码中虽然也声明了接口,也有实现类,但是在具体使用过程中并没有遵循依赖倒置原则。体现在上述的ItemManagerImpl类中,因为按照依赖倒置原则在ItemManagerImpl类中只能出现D层的ItemDao的信息。它应该只知道ItemDao,如果现在需要更换数据库,那么就需要更改ItemManagerImpl中的代码,将new ItemDao4MysqlImpl()修改为new ItemDao4OracleImpl(),但是这并不符合开闭原则,所以这里使用的这个依赖倒置并不完善,或者说是仅仅有了一个形式上的依赖倒置,但是本质上并没有改变ItemManagerImpl有依赖于具体实现类。

😄完善

如何修改上面的代码,做到符合依赖倒置的原则呢?这就需要用到反射这个强大的功能,首先要添加一个配置文件。
在配置文件中加上需要反射的类路径,在这个demo中需要反射的类是mysql实现类。
在这里插入图片描述
添加完配置文件中的信息后,需要有一个读取配置文件的类,来获取配置文件中的类路径信息

import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
/**
 * @Description: 读取配置文件
 */
public class PropertiesReader {
    public static String getValue(String key) {
        Properties properties = new Properties();
        FileInputStream fis = null;
        String value="";
        try {
            fis = new FileInputStream("application.properties");
            properties.load(fis);
            // 读取配置项
            value= properties.getProperty(key);
            return value;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {

            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return value;
    }
}

有了以上的这些准备后,现在开始修改ItemManagerImpl这个类中的依赖问题

new这个操作删除,修改为通过反射来获取对象。
通过使用反射加配置文件在构造函数中将itemDao给实例化出对象来。这样就符合了依赖倒置,这个时候在看ItemManagerImpl类中它的依赖中就只有ItemDao这个接口了。
在这里插入图片描述

后期项目中如果需要更换数据库,那这里去操作出数据库的类,就可以在配置文件中进行更换,只需将类路径更换即可。以上这些操作只是为了简单的描述出来,依赖倒置具体的实现和应用。实际开发过程中要考虑的还是很多的,比如对象怎么管理啊这些工作。

里式替换

定义

里氏替换原则的内容可以描述为: “派生类(子类)对象可以在程式中代替其基类(超类)对象。

具体应用

在上述的代码中其实就是基于里式替换实现的,虽然在定义中说是基类和派生类,但是接口同样适用里式替换的原则,根据里式替换原则,如果一个类通过实现一个接口来表达其行为,那么在使用接口时,任何实现该接口的类都应该能够替换该接口,而不会破坏程序的正确性。
具体体现在ItemDao itemDao=new ItemDao4MysqlImpl();虽然后面修改为了反射获取,通过类型转换为了ItemDao

itemDao=(ItemDao)Class.forName(PropertiesReader.getValue("itemDao")).newInstance();

但是这依然符合。

接口隔离

定义

接口隔离原则的核心思想是将庞大而臃肿的接口拆分为更小、更具体的接口,使得每个接口只包含客户端所需的方法。这样可以降低类和模块之间的耦合度,减少对不相关方法的依赖,提高代码的灵活性、可维护性和可复用性。
以下是接口隔离原则的几个要点:

  1. 接口应该精简而专注于特定的功能领域。不应该设计臃肿的接口,包含大量不相关的方法。

  2. 客户端不应该强制依赖于它不需要的接口。一个类或模块只应该依赖于它需要使用的接口,而不是依赖于多余的接口。

  3. 接口隔离原则鼓励根据不同的客户端需求定义多个小接口,而不是一个大而全的接口。这样可以提供更高的灵活性和可扩展性。

  4. 接口设计应该符合单一职责原则,即一个接口只负责定义一个单一的功能或角色。

具体应用

接口隔离原则在我们上述的依赖倒置这里其实就已经体现了,访问数据库的操作行为抽象为一个接口,这个接口包含了数据库操作的所有行为,而作为B层的ItemManagerImpl来说,它只依赖于接口,而具体的实现类单独写,如果后期需要添加信息的数据库,直接添加一个实现类即可,搭配着依赖倒置的原则和里式替换,通过反射去创建对象。程序的灵活性就大大提高了。
在这里插入图片描述

在这里插入图片描述

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

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

相关文章

cplex基础入门(一)

这边文章会以纯新手小白的视角,教会大家如何快速的搭建自己的cplex模型,做到求解模型不求人。 目录 一、引言 1、掌握数据类型及数据结构 2、常规Cplex编程方法 3、Cplex编程步骤 4、cplex 程序框架 5、创建模型 二、规划建模的入门求解案例 1、…

Python3数据分析与挖掘建模(3)探索性数据分析

1. 概述 探索性数据分析(Exploratory Data Analysis,EDA)是一种数据分析的方法,用于探索和理解数据集的特征、关系和分布等。EDA旨在揭示数据中的模式、异常值、缺失值等信息,并为后续的分析和建模提供基础。以下是关…

CISCN 2023 初赛 pwn——Shellwego 题解

这是一个用go语言写的elf程序,没有PIE。这也是本蒟蒻第一次解go pwn题,故在此记录以便参考。 而且,这还是一个全部符号表被抠的go elf,直接面对一堆不知名的函数实在有些应付不来,因此在比赛时委托逆向的队友把符号表…

​【指针与数组的恩怨情仇】

指针和数组的关系 指针指的是指针变量,不是数组,指针变量的大小是4/8个字节,是专门来存放地址的。数组也不是指针,数组是一块连续的空间,存放一组相同类型的数据的。 没有关系,但是它们之间有比较相似的地方…

【Netty】一行简单的writeAndFlush都做了哪些事(十八)

文章目录 前言一、源码分析1.1 ctx.writeAndFlush 的逻辑1.2 writeAndFlush 源码1.3 ChannelOutBoundBuff 类1.4 addMessage 方法1.5 addFlush 方法1.6 AbstractNioByteChannel 类 总结 前言 回顾Netty系列文章: Netty 概述(一)Netty 架构设…

好用的Chrome浏览器插件推荐(不定期更新)

好用的Chrome浏览器插件推荐 1.1 CSDN-浏览器助手1.2 Google 翻译1.3 JSON Viewer1.4 ModHeader - Modify HTTP headers1.5 Octotree - GitHub code tree 1.1 CSDN-浏览器助手 CSDN-浏览器助手 是一款集成本地书签、历史记录与 CSDN搜索(so.csdn.net) 的搜索工具 推荐&#x…

自动驾驶车载MCU开发修炼秘籍

目录 车载MCU开发修炼秘籍1、恩智浦 S32K1XX系列2、英飞凌 AURIX TC3XX3、嵌入式实时操作系统-FreeRTOS4、车载实时操作系统-AUTOSAR 车载MCU开发修炼秘籍 1、恩智浦 S32K1XX系列 S32K14X学习笔记(一)–S32K汽车MCU资源总结 S32K14X学习笔记&#xff1a…

第二章 数据类型、运算符与表达式

如何打开项目 如何打开已经存在的解决方案? 找到要打开的解决方案目录,进去之后双击后缀为.sln的文件即可打开该解决方案。 或者从最近打开项目中打开: Online Judge使用 OJ简介 在线判题系统(Online Judge,缩写OJ…

WebService接口测试

WebService的理解 WebService就是Web服务的意思,对应的应用层协议为SOAP(相当于HTTP协议),可理解为远程调用技术。 特点: 客户端发送的请求主体内容(请求报文)的格式为XML格式 接口返回的响…

【P36】JMeter 交替控制器(Interleave Controller)

文章目录 一、交替控制器(Interleave Controller)参数说明二、测试计划设计 一、交替控制器(Interleave Controller)参数说明 可以将内部的组件在线程迭代时交替执行;交替控制器内部一般会有多个取样器 选择线程组右…

黑马Redis视频教程高级篇(一:分布式缓存)

目录 分布式缓存 一、Redis持久化 1.1、RDB持久化 1.1.1、执行时机 1.1.2、RDB原理 1.1.3、小结 1.2、OF持久化 1.2.1、AOF原理 1.2.2、OF配置 1.2.3、AOF文件重写 1.3、RDB与AOF对比 二、Redis主从 2.1、搭建主从架构 2.1.1、集群结构 2.1.2、准备实例和配置 …

多层级table联动

elementui 多层级table联动: 引用: https://blog.csdn.net/weixin_44780971/article/details/130054925 https://blog.csdn.net/qq_42581563/article/details/114325920 需要了解的属性: select-all 全选的时候执行select : 选择…

linux高级---k8s中的五种控制器

文章目录 一、k8s的控制器类型二、pod与控制器之间的关系三、状态与无状态化对特点四、Deployment1、Deployment的资源清单文件2、在配置清单中调用deployment控制器3、镜像更新4、金丝雀发布5、删除Deployment 五、Statefulset六、DaemonSet1、daemonset的资源清单文件2、在配…

点到直线距离

点到直线距离最小二乘解释 推倒部分 形象描述是C到AB距离最短,也就是CD最短用数学语言描述是 m i n ∣ ∣ ( B − A ) λ A − C ∣ ∣ min||(B-A) \lambda A - C || min∣∣(B−A)λA−C∣∣ 其中 D ( B − A ) λ A D (B-A) \lambda A D(B−A)λA,其实本质…

使用Windbg动态调试目标进程的一般步骤及相关要点详解

目录 1、概述 2、将Windbg附加到已经启动起来的目标进程上,或者用Windbg启动目标程序 2.1、将Windbg附加到已经启动起来的目标进程上 2.2、用Windbg启动目标程序 2.3、Windbg关联到目标进程上会中断下来,输入g命令将该中断跳过去 3、分析实例说明 …

macOS Ventura 13.5beta2 (22G5038d)发布

系统介绍 黑果魏叔 6 月 1 日消息,苹果今日向 Mac 电脑用户推送了 macOS 13.5 开发者预览版 Beta 2 更新(内部版本号:22G5038d),本次更新距离上次发布隔了 12 天。 macOS Ventura 带来了台前调度、连续互通相机、Fac…

FPGA基于AXI 1G/2.5G Ethernet Subsystem实现千兆UDP通信 提供工程源码和技术支持

目录 1、前言2、我这里已有的UDP方案3、详细设计方案传统UDP网络通信方案本方案详细设计说明UDP层设计AXIS-FIFOAXI 1G/2.5G Ethernet Subsystem:输出 4、vivado工程详解5、上板调试验证并演示系统配置UDP数据回环测试注意事项 6、福利:工程代码的获取 1…

RK3588平台开发系列讲解(项目篇)RKNN-Toolkit2 的使用

平台内核版本安卓版本RK3588Linux 5.10Android 12文章目录 一、RKNN-Toolkit2安装二、模型转换和模型推理三、性能和内存评估沉淀、分享、成长,让自己和他人都能有所收获!😄 📢 NPU 是专门用于神经网络的处理单元。它旨在加速人工智能领域的神经网络算法,如机器视觉和自…

如何在 Linux 中进行网络地址转换 (NAT)?

网络地址转换(Network Address Translation,简称NAT)是一种在网络中使用的技术,它允许将私有网络中的IP地址映射到公共网络上,从而实现多个设备共享单个公共IP地址。在Linux系统中,我们可以使用一些工具和配…

《Web安全基础》01. 基础知识

基础 1:概念名词1.1:域名1.2:DNS1.3:网站开发语言1.4:后门1.5:Web1.6:Web 相关安全漏洞 2:数据包2.1:HTTP2.2:HTTPS2.3:请求数据包2.3.1&#xff…