• 控制反转 (IOC, Inversion of Control) 和 依赖注入 (DI, Dependency Injection)


    控制反转 (IoC, Inversion of Control)依赖注入 (DI, Dependency Injection)软件开发中两个经常一起使用和讨论的概念,尤其在面向对象编程和Spring框架的上下文中。让我们分别讨论它们:

    1. 控制反转 (IoC, Inversion of Control):

    控制反转是一种设计原则,主要目标是减少代码之间的耦合。"反转"是相对于传统程序控制流的,传统上,主程序负责调用其所需要的服务或组件。但在IoC中,这种控制流被“反转”了,也就是说,不是应用程序代码控制对象的创建和生命周期,而是外部容器或框架负责这些任务。

    例如,在传统的程序设计中,如果你的类需要数据库服务,你会在类中直接实例化一个数据库连接。但在使用IoC的系统中,类只会声明它需要数据库服务,然后外部系统(例如Spring容器)会负责提供这个服务。

    2. 依赖注入 (DI, Dependency Injection):

    依赖注入是实现IoC的一种方法。它涉及到在运行时动态地将依赖(即服务、对象、配置等)注入到需要它们的对象中。DI确保每个组件只关注自己的核心职责,并通过声明(而不是直接创建或查找)其依赖来完成其工作。

    回到上面的例子,如果一个类需要数据库服务,它不会直接创建一个数据库连接或使用单例模式查找一个。相反,它会声明对这种服务的需要(例如,通过Java的构造函数、setter方法或字段注解),然后外部容器(如Spring)负责将合适的服务“注入”到这个类中。

    总结:

    简而言之,IoC是一个广泛的概念,描述了由外部系统(容器或框架)而不是传统的主程序来控制程序的流程。DI是IoC的具体实现方式,通过注入依赖来实现控制反转,从而提高代码的模块性和可测试性。

    在Java的Spring框架中,IoC和DI是核心概念,它们使得应用程序组件之间的耦合度降低,从而提高了代码的可维护性和可测试性。


    提供一个简单的例子来描述控制反转 (IOC) 和依赖注入 (DI)。

    1. 传统方式(无IoC和DI):

    假设我们有一个BookStore类,这个类需要一个BookService来获取书籍:

    public class BookService {
        public String getBook() {
            return "Harry Potter";
        }
    }
    
    public class BookStore {
        private BookService bookService = new BookService();
    
        public String getBookTitle() {
            return bookService.getBook();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    上述例子中,BookStore类直接实例化了BookService。这种方式的问题是BookStore和特定的BookService实现紧密耦合在一起。

    2. 使用IoC和DI:

    首先,我们会定义一个BookService的接口,然后有多个实现类。接着,我们不会在BookStore内部直接创建BookService的实例,而是通过外部方式(构造函数、setter等)注入进来。

    public interface BookService {
        String getBook();
    }
    
    public class FictionBookService implements BookService {
        @Override
        public String getBook() {
            return "Harry Potter";
        }
    }
    
    public class ScienceBookService implements BookService {
        @Override
        public String getBook() {
            return "Brief History of Time";
        }
    }
    
    public class BookStore {
        private BookService bookService;
    
        public BookStore(BookService bookService) {
            this.bookService = bookService;
        }
    
        public String getBookTitle() {
            return bookService.getBook();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    在上述代码中,BookStore不再直接依赖于具体的BookService实现。你可以注入FictionBookServiceScienceBookService,这使得BookStore更加灵活和可测试。

    例如,当使用Spring框架时,你可以这样配置:

    <bean id="bookService" class="FictionBookService" />
    <bean id="bookStore" class="BookStore">
        <constructor-arg ref="bookService" />
    bean>
    
    • 1
    • 2
    • 3
    • 4

    或使用Java注解:

    @Service
    public class FictionBookService implements BookService { ... }
    
    @Autowired
    public BookStore(BookService bookService) { ... }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    通过这种方式,Spring容器负责创建BookService的实例并注入到BookStore中,实现了控制反转和依赖注入。

  • 相关阅读:
    Spark基础入门(01)—RDD
    【分享】科大讯飞星火认知大模型(初体验)
    一文搞定 Spring事务
    python将word文件转换成pdf文件
    flink安装与基础测试
    arduino32 esp32路舵机驱动板(开源可自制,附程序和固件以及烧录方法)
    基于SpringBoot的自行车租赁系统的设计与实现
    物理气相沉积半导体设备 PVD DSP/ARM+FPGA控制器设计
    请简要说明 Mysql 中 MyISAM 和 InnoDB 引擎的区别
    一个冒泡排序引发的思考
  • 原文地址:https://blog.csdn.net/weixin_43732424/article/details/133811399