十分钟搞懂依赖注入

简介: 依赖注入(DI)是软件开发中的关键技术,它将类的依赖关系转移至外部管理,提升了代码的模块化和可测试性。如同炒菜时调料不由厨师直接添加,而是由调料师准备并递送,程序员只需声明所需依赖,外部机制如DI容器会负责实例化并注入这些依赖。这样,类变得更灵活且易于测试,同时也促进了代码的模块化。例如,在Java中,可以通过构造函数注入Logger接口的不同实现(如ConsoleLogger和FileLogger),使Application类与其具体实现解耦。

依赖注入(Dependency Injection,简称DI)是一种在软件开发中常用的技术,它帮助我们将一个类的依赖关系从类内部转移到类的外部来管理。这样做的好处是提高了代码的模块化和可测试性。
想象一下,你正在做一道菜,这道菜需要用到盐、酱油和糖等调料。在传统的做法中,你可能会在炒菜的过程中直接往锅里加这些调料,也就是说,炒菜这个“类”直接管理了它的所有依赖(调料)。但是,如果某天你想换一种品牌的酱油试试,或者想在不改变炒菜过程的情况下,用这道菜的配方去做另一道菜,你就会发现这样做起来很麻烦。

依赖注入就像是有一个专门的调料师(依赖注入容器或者框架),他负责准备好所有的调料,并在你需要的时候递给你。你只需要告诉他你需要哪些调料(通过构造函数、属性或者方法参数等方式声明你的依赖),他就会帮你准备好。这样,你就可以专注于炒菜的过程,而不用担心调料的问题了。

在软件开发中,依赖注入也是这样的。你不需要在你的类里面直接创建依赖对象的实例,而是声明你需要的依赖,然后通过一个外部的机制(比如构造函数注入、属性注入或者方法注入)来提供这些依赖的实例。这样做的好处是,你的类变得更加灵活和可测试,因为你可以很容易地替换掉它的依赖,而不需要修改类的内部代码。同时,这也使得你的代码更加模块化,因为每个类都只需要关注它自己的职责,而不需要关心它的依赖是如何被创建和管理的。

以下是一个简单的依赖注入的实际例子,我们将使用Java语言来演示,但请注意,依赖注入的概念并不局限于Java,它同样适用于其他支持面向对象编程的语言。

假设我们有一个日志系统,其中有一个Logger接口,以及两个实现了这个接口的类:ConsoleLogger和FileLogger。现在,我们有一个Application类,它需要使用Logger来记录信息,但我们不想在Application类中直接创建Logger的实例,因为这样会使Application类与具体的日志实现紧密耦合,降低了代码的可测试性和可维护性。

我们可以通过依赖注入来解决这个问题。

首先,定义Logger接口和它的两个实现:

public interface Logger {  
    void log(String message);  
}  

public class ConsoleLogger implements Logger {  
    @Override  
    public void log(String message) {  
        System.out.println("Console: " + message);  
    }  
}  

public class FileLogger implements Logger {  
    private String filePath;  

    public FileLogger(String filePath) {  
        this.filePath = filePath;  
    }  

    @Override  
    public void log(String message) {  
        // 这里只是示意,实际中应该写入文件  
        System.out.println("File (" + filePath + "): " + message);  
    }  
}

然后,是Application类,它依赖于Logger接口:

public class Application {  
    private Logger logger;  

    // 通过构造函数注入Logger依赖  
    public Application(Logger logger) {  
        this.logger = logger;  
    }  

    public void doSomething() {  
        // 使用logger记录信息  
        logger.log("Doing something important...");  
        // 其他业务逻辑...  
    }  
}

最后,在应用程序的启动或配置部分,我们创建Logger的具体实现,并将其注入到Application实例中:

public class Main {  
    public static void main(String[] args) {  
        // 假设我们决定使用ConsoleLogger  
        Logger logger = new ConsoleLogger();  

        // 创建Application实例,并注入logger  
        Application app = new Application(logger);  

        // 使用Application实例  
        app.doSomething();  

        // 如果我们决定改用FileLogger,只需要在这里更改即可  
        // Logger logger = new FileLogger("app.log");  
        // Application app = new Application(logger);  
        // app.doSomething();  
    }  
}

在这个例子中,Application类通过其构造函数接收一个Logger类型的参数,这就是依赖注入的一个典型例子。通过这种方式,Application类不再需要知道它所使用的Logger的具体实现是什么,它只需要知道如何与Logger接口交互即可。这样,我们就可以轻松地更换Logger的实现,而无需修改Application类的代码。

相关文章
|
SQL 关系型数据库 数据库
Tortoise ORM入门之理论篇
Tortoise ORM入门之理论篇
2914 0
Tortoise ORM入门之理论篇
|
缓存 负载均衡 监控
【微服务】一文读懂网关概念+Nginx正反向代理+负载均衡+Spring Cloud Gateway(多栗子)
不知道什么是网关?正向代理?反向代理?负载均衡?负载均衡策略?Nginx和Gateway的区别?假如这些你都不知道,没关系,本文举了大量通俗易懂的例子来阐述了这些概念,保证小白也能看懂,并且最后还提到了gateway的一些配置。
13198 4
【微服务】一文读懂网关概念+Nginx正反向代理+负载均衡+Spring Cloud Gateway(多栗子)
|
4月前
|
域名解析 弹性计算 安全
阿里云上云步骤流程详解:云服务器+域名+备案+解析绑定实操指南
阿里云上云是企业与个人搭建网站、部署应用的基础路径,核心流程包含云服务器ECS购买、域名注册与实名、ICP备案、域名解析绑定四大环节,各环节环环相扣,缺一不可。以下从准备、购买、配置、上线全流程,详细拆解每一步操作,确保零基础用户也能顺利完成上云部署。
998 0
|
负载均衡 监控 Java
Spring Cloud Gateway 全解析:路由配置、断言规则与过滤器实战指南
本文详细介绍了 Spring Cloud Gateway 的核心功能与实践配置。首先讲解了网关模块的创建流程,包括依赖引入(gateway、nacos 服务发现、负载均衡)、端口与服务发现配置,以及路由规则的设置(需注意路径前缀重复与优先级 order)。接着深入解析路由断言,涵盖 After、Before、Path 等 12 种内置断言的参数、作用及配置示例,并说明了自定义断言的实现方法。随后重点阐述过滤器机制,区分路由过滤器(如 AddRequestHeader、RewritePath、RequestRateLimiter 等)与全局过滤器的作用范围与配置方式,提
Spring Cloud Gateway 全解析:路由配置、断言规则与过滤器实战指南
|
前端开发 开发者
响应式布局新利器:CSS Grid 的 `grid-template-areas` 实战
响应式布局新利器:CSS Grid 的 `grid-template-areas` 实战
|
运维 Kubernetes Cloud Native
什么是云原生?
云原生(Cloud Native)是一种充分利用云计算弹性和自动化能力的架构理念,核心思想包括以云为中心、模块化与松耦合、自动化运维及弹性容错。其关键技术涵盖容器化(如Docker)、编排调度(如Kubernetes)、微服务和DevOps等。相比传统架构,云原生具备敏捷性、弹性伸缩、高可用性和资源优化等优势,适用于互联网高并发业务、AI/大数据平台及企业转型场景。然而,落地面临技术复杂度高、组织文化转型及安全合规挑战。未来发展趋势包括混合多云管理、智能化运维及WebAssembly等轻量化技术。Gartner预测,到2025年超95%新应用将采用云原生模式开发。
4216 3
|
XML 设计模式 Java
这6种 Spring 依赖注入方式,你都会吗?
这6种 Spring 依赖注入方式,你都会吗?
2530 1
这6种 Spring 依赖注入方式,你都会吗?
Unity精华☀️GetInstanceID 和 GetHashCode 的区别
Unity精华☀️GetInstanceID 和 GetHashCode 的区别
|
Java 编译器 Spring
面试突击78:@Autowired 和 @Resource 有什么区别?
面试突击78:@Autowired 和 @Resource 有什么区别?
18368 7
|
人工智能 前端开发 Java
DDD四层架构和MVC三层架构的个人理解和学习笔记
领域驱动设计(DDD)是一种以业务为核心的设计方法,与传统MVC架构不同,DDD将业务逻辑拆分为应用层和领域层,更关注业务领域而非数据库设计。其四层架构包括:Interface(接口层)、Application(应用层)、Domain(领域层)和Infrastructure(基础层)。各层职责分明,避免跨层调用,确保业务逻辑清晰。代码实现中,通过DTO、Entity、DO等对象的转换,结合ProtoBuf协议,完成请求与响应的处理流程。为提高复用性,实际项目中可增加Common层存放公共依赖。DDD强调从业务出发设计软件,适应复杂业务场景,是微服务架构的重要设计思想。