软件设计原则-依赖倒置原则讲解以及代码示例

简介: 依赖倒置原则(Dependency Inversion Principle,DIP)是面向对象设计中的一个重要原则,由Robert C. Martin提出。依赖倒置原则的核心思想是:高层模块不应该依赖于低层模块,二者都应该依赖于抽象。抽象不应该依赖于具体实现细节,而具体实现细节应该依赖于抽象。这意味着我们在进行系统设计时,应该尽量使用抽象类或接口来定义对象之间的依赖关系,而不是直接依赖于具体的实现类

依赖倒置原则

一,介绍

1.前言

依赖倒置原则(Dependency Inversion Principle,DIP)是面向对象设计中的一个重要原则,由Robert C. Martin提出。

依赖倒置原则的核心思想是:高层模块不应该依赖于低层模块,二者都应该依赖于抽象。抽象不应该依赖于具体实现细节,而具体实现细节应该依赖于抽象。这意味着我们在进行系统设计时,应该尽量使用抽象类或接口来定义对象之间的依赖关系,而不是直接依赖于具体的实现类。

2.何时使用依赖倒置原则

    1. 在编写高层模块时:依赖倒置原则要求高层模块不应该直接依赖于低层模块,而是通过抽象接口或抽象类来进行依赖。这样可以使得高层模块与底层模块解耦,从而提高系统的灵活性和可维护性。
    2. 在进行模块间的解耦时:依赖倒置原则可以帮助我们将模块之间的依赖关系反转,从而降低了模块间的耦合度。通过引入抽象接口或抽象类作为依赖关系的中介,可以使得模块之间更加独立,易于替换和扩展。
    3. 在应用依赖注入(Dependency Injection)时:依赖注入是一种实现依赖倒置的具体方式,它通过外部将依赖对象注入到需要使用的对象中,从而减少了对象之间的直接依赖关系。依赖注入可以使得系统更加灵活,易于测试和扩展。
    4. 在进行单元测试时:依赖倒置原则可以帮助我们编写更加可测试的代码。通过将依赖对象抽象化,并使用接口或抽象类进行依赖注入,可以方便地替换依赖对象,从而使得单元测试更加简单和可靠。

    二,代码示例

    为了更详细地介绍依赖倒置原则,我们可以通过一个例子来说明:

    假设有一个订单管理系统,系统中包含了订单类和数据库类,订单类负责处理订单相关的业务逻辑,而数据库类负责与数据库交互。最初的设计可能会像这样:

     

    class Order {
        private Database database;
        // 省略构造方法和其他属性方法
        public void save() {
            database.save(this);
        }
    }
    class Database {
        public void save(Order order) {
            // 保存订单到数据库
        }
    }

    image.gif

    在这个设计中,订单类直接依赖于具体的数据库类,这样一来,如果将来需要更换数据库操作方式,就需要修改订单类的代码,违反了开闭原则。

    为了符合依赖倒置原则,我们可以进行重构。首先,定义一个抽象类或接口`Database`:

    interface Database {
        void save(Order order);
    }

    image.gif

    然后,订单类通过构造函数或setter方法注入一个`Database`对象,从而将具体的数据库实现与订单类解耦:

    class Order {
        private Database database;
        public Order(Database database) {
            this.database = database;
        }
        // 省略其他属性方法
        public void save() {
            database.save(this);
        }
    }

    image.gif

    当需要使用特定的数据库实现时,我们只需要创建一个实现了`Database`接口的具体类,并将其传递给订单类:

     

    这样,订单类与具体的数据库实现解耦,而且我们可以轻松地使用不同的数据库实现,而无需修改订单类的代码。

    依赖倒置原则的目的是降低模块之间的耦合度,提高系统的灵活性和可维护性。通过面向抽象编程,并通过依赖注入的方式实现对象之间的解耦,可以使系统更容易扩展和修改,同时也方便进行单元测试和模块替换。

    总结起来,依赖倒置原则要求我们将高层模块的设计依赖于抽象,而不是具体实现细节。它是面向对象设计中的重要原则之一,在软件开发中具有广泛的适用性和重要性。

    三,优缺点

    优点:

      1. 降低模块间的耦合度:依赖倒置原则可以将模块之间的直接依赖关系转变为对抽象接口或抽象类的依赖,从而降低了模块之间的耦合度。这样,当一个模块发生变化时,对其他模块的影响也会减少,提高了系统的灵活性。
      2. 提高代码的可扩展性:通过引入抽象接口或抽象类,依赖倒置原则使得系统更易于扩展。当需要添加新的功能时,只需要针对抽象进行扩展,而不需要修改现有的代码。这有助于降低对原有代码的影响范围,提高了代码的可维护性和可复用性。
      3. 促进代码的测试和调试:依赖倒置原则可以帮助我们编写更加可测试和可调试的代码。通过引入抽象接口或抽象类,并使用依赖注入等机制,可以方便地替换依赖对象,从而使得单元测试更加简单和可靠。
      4. 支持多态性:依赖倒置原则支持多态性的应用。通过面向抽象编程,可以针对抽象类型进行编程,而不关心具体的实现类。这样可以提高代码的灵活性和可复用性。

      缺点:

        1. 增加了系统的复杂性:引入抽象接口或抽象类,以及依赖注入等机制,会增加系统的复杂性。需要额外的设计和开发工作来定义和管理抽象接口,并实现依赖注入。
        2. 需要对系统进行全面设计:依赖倒置原则需要在系统设计的早期考虑,需要合理划分抽象接口和实现类,并建立合适的依赖关系。如果在系统设计已经完成的情况下才引入依赖倒置原则,可能需要大量的重构工作。
        3. 可能增加运行时的性能开销:由于依赖倒置原则需要通过抽象接口进行运行时的依赖解析和注入,可能会带来一定的性能开销。特别是在系统规模较大且依赖关系较复杂的情况下,可能需要额外的开销来管理依赖关系。
        目录
        相关文章
        软件设计原则-迪米特原则讲解以及代码示例
        迪米特原则(Law of Demeter,简称LoD)也被称为最少知识原则(Least Knowledge Principle,LKP),是面向对象设计的一种重要原则。迪米特原则的核心思想是尽量减少对象之间的交互,使得系统中的模块能够相对独立地变化。
        125 0
        软件设计原则-迪米特原则讲解以及代码示例
        软件设计原则-接口隔离原则讲解以及代码示例
        接口隔离原则(Interface Segregation Principle,ISP)是面向对象设计中的一个原则,提倡使用多个专门的接口,而不使用单一的大接口。它最早由Robert C. Martin在其《敏捷软件开发:原则、模式与实践》一书中提出。 接口隔离原则的核心思想是:客户端不应该依赖于它不需要的接口。也就是说,一个类或模块不应该强迫它的用户去依赖无用的接口。相反,应该将大接口拆分成多个小接口,符合客户端的需求,使客户端只依赖于它真正需要的接口。 接口隔离原则的目标是降低类或模块之间的耦合度,提高代码的可维护性、可扩展性和可测试性。通过使用多个专门的接口,我们可以避免类或模块之间出现不
        116 0
        |
        设计模式 Java 关系型数据库
        软件设计原则-开闭原则讲解以及代码示例
        开闭原则(Open-Closed Principle,OCP)是面向对象设计中的一条重要原则,它由Bertrand Meyer在其著作《面向对象软件构造》中提出,并成为SOLID原则之一。 开闭原则的核心思想是:软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。简单来说,就是在不修改已有代码的情况下,通过扩展来实现新的功能或变化。
        451 0
        |
        测试技术
        软件设计原则-里氏替换原则讲解以及代码示例
        里氏替换原则(Liskov Substitution Principle,LSP)是面向对象设计中的一条重要原则,它由Barbara Liskov在1987年提出。 里氏替换原则的核心思想是:父类的对象可以被子类的对象替换,而程序的行为不会发生变化。也就是说,如果一个类型A是另一个类型B的子类型,那么在任何使用B的地方都可以使用A,而不会引起错误或异常。
        515 0
        软件设计原则-合成复用原则讲解以及代码示例
        合成复用原则(Composition/Aggregation Reuse Principle,CARP)是面向对象设计的一种重要原则,也被称为组合/聚合复用原则。它强调通过组合(Composition)或聚合(Aggregation)关系来达到代码复用的目的,而不是通过继承关系。
        192 0
        |
        设计模式 算法
        原则的重要性(单一职责原则-开放封闭原则)一
        原则的重要性(单一职责原则-开放封闭原则)一
        93 0
        |
        uml
        【程序设计】6大设计原则之依赖倒置
        【程序设计】6大设计原则之依赖倒置
        151 0
        【程序设计】6大设计原则之依赖倒置
        【程序设计】6大设计原则之单一职责
        【程序设计】6大设计原则之单一职责
        113 0
        【程序设计】6大设计原则之单一职责
        |
        设计模式
        【设计模式】软件设计七大原则 ( 依赖倒置原则 | 代码示例 )(三)
        【设计模式】软件设计七大原则 ( 依赖倒置原则 | 代码示例 )(三)
        113 0
        【设计模式】软件设计七大原则 ( 依赖倒置原则 | 代码示例 )(三)
        |
        设计模式 Oracle 关系型数据库
        【设计模式】软件设计七大原则 ( 合成复用原则 | 代码示例 )
        【设计模式】软件设计七大原则 ( 合成复用原则 | 代码示例 )
        291 0
        【设计模式】软件设计七大原则 ( 合成复用原则 | 代码示例 )