JAVA设计模式:依赖倒转原则(DIP)在Spring框架中的实践体现

文章目录

  • 一、DIP原则深度解析
    • 1.1 核心定义
    • 1.2 现实比喻
  • 二、Spring中的DIP实现机制
    • 2.1 传统实现 vs Spring实现对比
  • 三、Spring中DIP的完整示例
    • 3.1 领域模型定义
    • 3.2 具体实现
    • 3.3 高层业务类
      • 3.4 配置类
  • 四、Spring实现DIP的关键技术
    • 4.1 依赖注入方式对比
    • 4.2 自动装配注解
  • 五、DIP在Spring中的实践建议
  • 六、典型应用场景
    • 6.1 数据库切换
    • 6.2 多支付渠道
  • 七、常见误区及规避
  • 八、Spring Boot中的最佳实践
  • 九、总结

在这里插入图片描述

一、DIP原则深度解析

1.1 核心定义

依赖倒转原则(Dependency Inversion Principle) :高层模块不应该依赖低层模块,二者都应该依赖抽象 。抽象不应该依赖细节,细节应该依赖抽象。

1.2 现实比喻

想象一家智能家居系统:

  • 高层模块:智能家居控制中心(业务逻辑)

  • 低层模块:具体设备(灯泡、空调、摄像头)

  • 抽象接口:统一设备控制协议

  • 控制中心通过标准协议控制设备,无需关心具体设备型号。新增设备只需实现协议接口,无需修改控制中心代码。

二、Spring中的DIP实现机制

Spring框架通过两大核心功能实现DIP:

  1. 控制反转(IoC):将对象创建权交给容器
  2. 依赖注入(DI):通过构造函数/Setter/字段注入依赖

2.1 传统实现 vs Spring实现对比

// 传统方式(违反DIP)
public class OrderService {
    private MySQLOrderDao orderDao = new MySQLOrderDao(); // 直接依赖具体实现
    
    public void createOrder() {
        orderDao.save();
    }
}

// Spring实现(符合DIP)
@Service
public class OrderService {
    private final OrderRepository orderRepository; // 依赖抽象接口
    
    @Autowired
    public OrderService(OrderRepository orderRepository) {
        this.orderRepository = orderRepository;
    }
}

@Repository
public class JpaOrderRepository implements OrderRepository {
    // 实现接口
}

三、Spring中DIP的完整示例

3.1 领域模型定义

// 抽象层
public interface PaymentGateway {
    void processPayment(BigDecimal amount);
}

public interface NotificationService {
    void sendNotification(String message);
}

3.2 具体实现

// 支付实现
@Component("alipay")
public class AlipayGateway implements PaymentGateway {
    @Override
    public void processPayment(BigDecimal amount) {
        System.out.println("支付宝支付:" + amount);
    }
}

// 通知实现 
@Component
public class EmailNotification implements NotificationService {
    @Override
    public void sendNotification(String message) {
        System.out.println("发送邮件:" + message);
    }
}

3.3 高层业务类

@Service
public class OrderProcessingService {
    private final PaymentGateway paymentGateway;
    private final NotificationService notificationService;

    @Autowired
    public OrderProcessingService(
        @Qualifier("alipay") PaymentGateway paymentGateway,
        NotificationService notificationService) {
        
        this.paymentGateway = paymentGateway;
        this.notificationService = notificationService;
    }

    public void completeOrder(Order order) {
        paymentGateway.processPayment(order.getTotal());
        notificationService.sendNotification("订单完成,金额:" + order.getTotal());
    }
}

3.4 配置类

@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
    // 可通过@Bean配置更复杂的依赖关系
}

四、Spring实现DIP的关键技术

4.1 依赖注入方式对比

注入方式代码示例适用场景
构造器注入@Autowired OrderService(OrderRepository repo)推荐首选方式,保证不可变
Setter注入@Autowired void setRepo(OrderRepository repo)可选依赖
字段注入@Autowired private OrderRepository repo;不推荐,测试困难

4.2 自动装配注解

  • @Autowired:按类型自动装配
  • @Qualifier:指定具体实现bean
  • @Primary:设置优先注入的bean

五、DIP在Spring中的实践建议

  1. 接口先行 :先定义抽象接口,再实现具体类

    // 先定义仓库接口
    public interface UserRepository {
        User findById(Long id);
        void save(User user);
    }
    
    // 再实现JPA版本
    @Repository
    public class JpaUserRepository implements UserRepository {
        // 具体实现
    }
    
  2. 善用Profile配置 :不同环境切换实现类

    @Profile("dev")
    @Service
    public class MockPaymentService implements PaymentService {}
    
    @Profile("prod")
    @Service
    public class RealPaymentService implements PaymentService {}
    
  3. 循环依赖处理:使用Setter注入或@Lazy注解打破循环依赖

    @Service
    public class ServiceA {
        private final ServiceB serviceB;
        
        @Autowired
        public ServiceA(@Lazy ServiceB serviceB) {
            this.serviceB = serviceB;
        }
    }
    

六、典型应用场景

6.1 数据库切换

// 通用仓库接口
public interface ProductRepository extends JpaRepository<Product, Long> {}

// MySQL实现
@Profile("mysql")
@Repository
public interface MysqlProductRepository extends ProductRepository {}

// MongoDB实现 
@Profile("mongodb")
@Repository
public interface MongoProductRepository extends ProductRepository {}

6.2 多支付渠道

@Component
public class PaymentGatewayRouter {
    private final Map<String, PaymentGateway> gateways;
    
    @Autowired
    public PaymentGatewayRouter(List<PaymentGateway> gatewayList) {
        this.gateways = gatewayList.stream()
            .collect(Collectors.toMap(
                g -> g.getClass().getAnnotation(GatewayType.class).value(),
                Function.identity()
            ));
    }
    
    public PaymentGateway getGateway(String type) {
        return gateways.get(type);
    }
}

七、常见误区及规避

  1. 过度抽象:为每个类都创建接口 -> 仅在确实需要多种实现时创建接口
  2. 忽略单实现:单个实现类也要通过接口注入 -> 保持架构一致性
  3. 滥用@Autowired:在工具类中直接注入 -> 优先使用构造函数注入
  4. 循环依赖:A依赖B,B又依赖A -> 使用@Lazy或重构代码结构

八、Spring Boot中的最佳实践

// 自动配置示例
@Configuration
@ConditionalOnClass(DataSource.class)
public class DatabaseAutoConfiguration {
    
    @Bean
    @ConditionalOnProperty(name = "db.type", havingValue = "mysql")
    public DataSource mysqlDataSource() {
        return new MysqlDataSource();
    }
    
    @Bean
    @ConditionalOnProperty(name = "db.type", havingValue = "postgres")
    public DataSource postgresDataSource() {
        return new PostgresDataSource();
    }
}
  • 通过Spring Boot的条件注解,实现不同环境自动装配不同的实现类,完美体现DIP原则。

九、总结

在Spring框架中实践DIP原则的关键:
✅ 通过接口定义抽象契约
✅ 利用依赖注入解耦组件
✅ 善用Spring的自动装配机制
✅ 保持适度的抽象层级
✅ 结合设计模式增强扩展性

掌握这些技巧,Spring应用将具备:

  • 更高的可测试性
  • 更好的可维护性
  • 更强的扩展能力
  • 更清晰的架构分层

  • 记住:依赖倒转不是目标,而是实现软件高质量设计的手段。在实际开发中,要平衡原则与实践需求,避免陷入过度设计的陷阱。

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

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

相关文章

JVM栈溢出线上环境排查

#查看当前Linux系统进程ID、线程ID、CPU占用率&#xff08;-eo后面跟想要展示的列&#xff09; ps H -eo pid,tid,%cpups H -eo pid,tid,%cpu |grep tid #使用java jstack 查看进程id下所有线程id的情况 jstack pid 案例2 通过jstack 排查死锁问题 #启动java代码 jstack 进…

Langchain+讯飞星火大模型Spark Max调用

1、安装langchain #安装langchain环境 pip install langchain0.3.3 openai -i https://mirrors.aliyun.com/pypi/simple #灵积模型服务 pip install dashscope -i https://mirrors.aliyun.com/pypi/simple #安装第三方集成,就是各种大语言模型 pip install langchain-comm…

Gradle配置指南:深入解析settings.gradle.kts(Kotlin DSL版)

文章目录 Gradle配置指南&#xff1a;深入解析settings.gradle.kts&#xff08;Kotlin DSL版&#xff09;settings.gradle.kts 基础配置选项单项目配置多项目配置 高级配置选项插件管理&#xff08;Plugin Management&#xff09;基础配置模板案例&#xff1a;Android项目标准配…

php twig模板引擎详细使用教程

php twig模板引擎 1. 什么是Twig模板引擎 Twig是一个强大且灵活的PHP模板引擎&#xff0c;它提供了一种更简洁和可扩展的方法来创建PHP应用程序的视图层。Twig模板引擎旨在将设计与业务逻辑分离&#xff0c;并为开发人员提供一种更加清晰和易于维护的方式来构建网页。Twig由S…

Java后端之AOP

AOP&#xff1a;面向切面编程&#xff0c;本质是面向特定方法编程 引入依赖&#xff1a; <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency>示例&#xff1a;记录…

vim的多文件操作

[rootxxx ~]# vim aa.txt bb.txt cc.txt #多文件操作 next #下一个文件 prev #上一个文件 first #第一个文件 last #最后一个文件 快捷键: ctrlshift^ #当前和上个之间切换 说明&#xff1a;快捷键ctrlshift^&#xff0c…

DataSecOps的要点

2020年首次提出&#xff0c;DataSecOps是一种敏捷、全面、内置安全的 方法&#xff0c;用于协调不断变化的数据及其用户&#xff0c;旨在快速提供数据价值&#xff0c; 同时确保数据的私密性、安全性和良好的管理。 强调数据全生命周 期流转运营过程中的内嵌安全属性&#x…

实用工具推荐----wsl安装

一&#xff1a;Win设置修改 Win 搜索 ”启用或关闭windows 功能“ 将如下内容选中 点击升级 重启电脑 二&#xff1a;安装步骤 参考官方文档 适用于 Linux 的 Windows 子系统文档 | Microsoft Learn 下载wsl ubantu发行包 旧版 WSL 的手动安装步骤 | Microsoft Learn 将u…

如何建设一个企业级的数据湖

建设一个企业级的数据湖是一项复杂且系统化的工程&#xff0c;需要从需求分析、技术选型、架构设计到实施运维等多个方面进行综合规划和实施。以下是基于我搜索到的资料&#xff0c;详细阐述如何建设企业级数据湖的步骤和关键要点&#xff1a; 一、需求分析与规划 明确业务需…

如何在 macOS 上安装 PIP ?

PIP 是任何 Python 开发人员必备的工具&#xff0c;因为它简化了安装和管理 Python 包的过程。本教程是为 macOS 用户量身定制的&#xff0c;并假设对使用终端有基本的了解。 必备条件 在安装 PIP 之前&#xff0c;必须确保您的系统上已经安装了 Python。Python 3.4 及更高版…

Kotlin开发(六):Kotlin 数据类,密封类与枚举类

引言 想象一下&#xff0c;你是个 Kotlin 开发者&#xff0c;敲着代码忽然发现业务代码中需要一堆冗长的 POJO 类来传递数据。烦得很&#xff1f;别急&#xff0c;Kotlin 贴心的 数据类 能帮你自动生成 equals、hashCode&#xff0c;直接省时省力&#xff01;再想想需要多种状…

多版本并发控制:MVCC的作用和基本原理

多版本并发控制&#xff1a;MVCC的作用和基本原理 1、MVCC简介1.1 快照读与当前读的区别1.1.1 快照读1.1.2 当前读 1.2 数据库的读写问题1.3 MVCC的作用 2、MVCC实现原理之ReadView2.1 什么是ReadView2.2 ReadView的设计思路2.3 MVCC整体操作流程 1、MVCC简介 1.1 快照读与当前…

Docker—搭建Harbor和阿里云私有仓库

Harbor概述 Harbor是一个开源的企业级Docker Registry管理项目&#xff0c;由VMware公司开发。‌它的主要用途是帮助用户迅速搭建一个企业级的Docker Registry服务&#xff0c;提供比Docker官方公共镜像仓库更为丰富和安全的功能&#xff0c;特别适合企业环境使用。‌12 Harb…

HarmonyOS:创建应用静态快捷方式

一、前言 静态快捷方式是一种在系统中创建的可以快速访问应用程序或特定功能的链接。它通常可以在长按应用图标&#xff0c;以图标和相应的文字出现在应用图标的上方&#xff0c;用户可以迅速启动对应应用程序的组件。使用快捷方式&#xff0c;可以提高效率&#xff0c;节省了查…

从表人的相关单词聊起

英文单词是繁多的&#xff0c;甚至海量的&#xff0c;这和老外的思维方式有关&#xff0c;他们通常会为同一类事物的具体的东西或子类事物也专门创建一个单词来进行表达、表示或应对&#xff0c;这增加了表达的直接性和精确性&#xff0c;但是&#xff0c;也轻而易举地就创建出…

低代码系统-产品架构案例介绍、轻流(九)

轻流低代码产品定位为零代码产品&#xff0c;试图通过搭建来降低企业成本&#xff0c;提升业务上线效率。 依旧是从下至上&#xff0c;从左至右的顺序 名词概述运维层底层系统运维层&#xff0c;例如上线、部署等基础服务体系内置的系统能力&#xff0c;发消息、组织和权限是必…

2025年美赛B题-结合Logistic阻滞增长模型和SIR传染病模型研究旅游可持续性-成品论文

模型设计思路与创新点&#xff1a; 建模的时候应该先确定我们需要建立什么类的模型&#xff1f;优化类还是统计类&#xff1f;这个题需要大量的数据分析&#xff0c;因此我们可以建立一个统计学模型。 统计学建模思路&#xff1a;观察规律&#xff0c;建立模型&#xff0c;参…

自由学习记录(32)

文件里找到切换颜色空间 fgui中的 颜色空间是一种总体使用前的设定 颜色空间&#xff0c;和半透明混合产生的效果有差异&#xff0c;这种问题一般可以产生联系 动效就是在fgui里可以编辑好&#xff0c;然后在unity中也准备了对应的调用手段&#xff0c;可以详细的使用每一个具…

【2025AI发展预测】2.2025的风口与发展,我们如何主动拥抱这一浪潮

个人主页&#xff1a;Icomi 大家好我是一颗米&#xff0c;本系列文章包含我个人的一些思考见解&#xff0c;以及在网上看到的相关资讯&#xff0c;结合本人的认识&#xff0c;在那基础上进行加工输出&#xff0c;希望能帮助到各位&#xff0c;若您对本系列感兴趣&#xff0c;欢…

操作系统(Linux Kernel 0.11Linux Kernel 0.12)解读整理——内核初始化(main init)之硬盘初始化

前言 对硬盘和软盘块设备上数据的读写操作是通过中断处理程序进行的。内核每次读写的数据量以一个逻辑块(1024 字节)为单位&#xff0c;而块设备控制器则是以扇区(512字节)为单位访问块设备。在处理过程中&#xff0c;内核使用了读写请求项等待队列来顺序地缓冲一次读写多个逻…