文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

依赖倒置,究竟什么被倒置了?

2024-11-29 20:41

关注

什么是依赖倒置?

依赖倒置原则,英文为:Dependency inversion principle(简称DIP),也是 Robert C. Martin提出的 SOLID原则中的一种,老规矩,还是先看看作者 Robert C. Martin 对接口依赖倒置原则是如何定义的:

The Dependency Inversion Principle (DIP) states that high-level
modules should not depend on low-level modules; both should 
depend on abstractions. Abstractions should not depend on details.
Details should depend upon abstractions.

通过作者对依赖倒置的定义,可以总结出其核心思想是:高层模块不应该依赖低层模块,两者都应该依赖于抽象。抽象不应该依赖于细节,细节应该取决于抽象。

直接依赖的问题

对于上述依赖倒置的定义,如何理解呢?我们先来看下传统这种直接依赖会存在什么问题?如下为一张直接依赖的关系图:

在上图中,高层组件 ObjectA直接依赖于低层组件 ObjectB,高层组件的重用机会受到限制,因为任何对低层组件的更改都会直接影响高层组件。

为了更好的说明直接依赖的问题,这里以一个真实的电商场景为例进行说明,其中有一个高层模块 OrderService用于处理订单,这个高层模块依赖于一个低层模块 OrderRepository来存储和检索订单数据。示例代码如下:

// 高层模块:OrderService
public class OrderService {
    private MySQLOrderRepository mySQLRepository;

    public OrderService(MySQLRepository mySQLRepository) {
        this.mySQLRepository = mySQLRepository;
    }

    public void createOrder(Order order) {
        // 一些业务逻辑
        mySQLRepository.save(order);
    }
}

// 低层模块:MySQLRepository
public class MySQLRepository {
    public void save(Order order) {
        // 使用 MySQL数据库保存订单
    }
}

在上述例子中,OrderService直接依赖于 OrderRepository,这种设计存在几个缺点:

那么,对于这些缺点,该如何解决呢?接下来我们将重点讲解。

如何实现依赖倒置?

这里提供两种主流的解决方案。

方案一:引入抽象层

通过低级组件实现高级组件的接口,要求低级组件包依赖于高级组件进行编译,从而颠倒了传统的依赖关系,如下图:

图1中,高层对象A依赖于底层对象B的实现;图2中,把高层对象A对底层对象的需求抽象为一个接口A,底层对象B实现了接口A,这就是依赖反转。

因此,上面的问题我们也可以通过引入一个抽象层 OrderRepository来解耦高层模块和低层模块,整个关系图如下:

通过这种方式,OrderService依赖于 OrderRepository接口而不是具体实现 MySQLRepository。这样,我们可以轻松替换低层实现而无需修改高层模块,修改后的代码如下:

// 高层模块:OrderService
public class OrderService {
    private OrderRepository orderRepository;

    public OrderService(OrderRepository orderRepository) {
        this.orderRepository = orderRepository;
    }

    public void placeOrder(Order order) {
        // 一些业务逻辑
        orderRepository.save(order);
    }
}

// 抽象层:OrderRepository接口
public interface OrderRepository {
    void save(Order order);
}

// 低层模块:MySQLRepository实现
public class MySQLRepository implements OrderRepository {
    public void save(Order order) {
        // 使用MySQL数据库保存订单
    }
}

// 另一个低层模块:PostgreSQLRepository实现
public class PostgreSQLRepository implements OrderRepository {
    public void save(Order order) {
        // 使用PostgreSQL数据库保存订单
    }
}

在应用程序中,我们可以灵活选择使用哪种具体实现,也可以把数据库的选择做成配置:

OrderRepository orderRepository = new MySQLRepository(); // 或 new PostgreSQLRepository();
OrderService orderService = new OrderService(orderRepository);

通过这种方式,OrderService变得更具重用性、可测试性更强,并且与具体的存储实现解耦,满足依赖倒置原则的要求。

方案二:引入抽象层升级版

尽管方式一也实现了依赖倒置,但是这种实现方式高层组件以及组件是封装在一个包中,对低层组件的重用会差一些,因此,另一种更灵活的解决方案是将抽象组件提取到一组独立的包/库中,如下图:

因此,上述电商示例的依赖关系会变成下图:

这种实现方式将每一层分离成自己的封装,鼓励任何层的再利用,提供稳健性和移动性。

两种方案的核心思想都是一样的,只是在灵活性和组件复用的考虑上略有差异。

依赖倒置的实例

在 Java语言中,使用依赖倒置原则的框架或者技术点有很多,这里列举2个比较较常用的例子:

1.Spring

Spring框架的核心之一是依赖注入(Dependency Injection, DI),这是依赖倒置原则的一个实现。通过Spring容器管理对象的创建和依赖关系,可以使得高层模块和低层模块都依赖于抽象。Spring支持构造器注入、setter注入和接口注入等多种方式。

2.Java SPI

Java SPI(Service Provider Interface)机制也体现了依赖倒置原则,SPI机制通过定义接口和服务提供者(Service Providers),使得高层模块(使用者)和低层模块(提供者)之间的依赖关系可以通过接口进行解耦。具体来说,高层模块依赖于抽象(接口),而不是具体的实现,从而实现了依赖倒置原则。

JDBC(Java Database Connectivity)就是使用 SPI机制来加载和注册数据库驱动程序,使得应用程序可以动态地使用不同的数据库而无需修改代码。

JDBC SPI的工作原理:

总结

本文通过一个电商示例分析了什么是依赖倒置原则,并且提出了依赖倒置的两种实现风格,通过引入抽象层,可以降低系统的耦合度,提升系统的扩展性和可维护性。因此,在实际开发中,我们应当始终遵循依赖倒置原则,设计灵活、可扩展的系统架构,从而应对复杂多变的业务需求。

来源:猿java内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯