设计模式-依赖注入模式

news2024/11/20 1:45:35
设计模式专栏

    • 模式介绍
    • 模式特点
    • 应用场景
    • 依赖注入和控制反转的区别
    • 代码示例
      • Java实现依赖注入模式
      • Python实现依赖注入模式
    • 依赖注入模式在spring中的应用


模式介绍

依赖注入(Dependency Injection,简称DI)是一种面向对象编程中的设计模式,它的目的是将一个对象所依赖的其他对象的创建过程从该对象本身中分离出来,以便更好地实现解耦和可测试性。

在DI模式中,对象不是通过自己创建所需要的依赖对象,而是通过构造函数、属性或接口传递进来。主要有以下几种方式:

  1. 构造函数注入(Constructor Injection):依赖对象通过被依赖对象的构造函数传入。这种方式是DI的主要方式,也是最简单的一种方式。它可以保证依赖对象的创建和注入是在同一时间完成的,因此可以确保依赖对象的可用性。适用于依赖对象需要在整个对象生命周期中都存在的情况,例如一个数据库连接对象。
  2. 属性注入(Property Injection):依赖对象通过被依赖对象的公共属性进行注入。
  3. 接口注入(Interface Injection):依赖对象通过实现被依赖对象的接口进行注入。

依赖注入的意义在于:

  1. 保证客户类仅仅与其依赖的服务类耦合,而不与服务类的子类型耦合,使得程序符合OCP或依赖于抽象类型原则。
  2. 不需声明全局公共的服务类对象,而是通过依赖注入(伸手-等待)来获取:在接受注入时声明所依赖的服务对象(伸手),框架会在初始化时将对象传递进来(等待)。

在这里插入图片描述

模式特点

依赖注入的主要特点包括:

  1. 降低耦合度 :依赖注入的核心思想是将对象之间的依赖关系分离出来,将原本紧耦合的对象变得松耦合,使得各个模块之间的依赖关系减少,有利于代码的复用和测试。
  2. 提高可扩展性 :由于依赖关系是通过外部方式注入的,因此当需要添加新的功能或模块时,只需要在配置文件中添加新的依赖关系,而不需要修改原有的代码,从而提高了系统的可扩展性。
  3. 便于测试和调试 :通过外部方式注入依赖关系,可以很容易地模拟和控制依赖对象的行为,便于进行单元测试和调试。
  4. 增强代码的可读性和可维护性 :通过使用依赖注入,代码更加清晰易懂,同时也可以减少代码中的硬编码,使得代码更加灵活、可维护。

在这里插入图片描述

应用场景

依赖注入模式的应用场景主要包括以下几个方面:

  1. 单元测试 :在单元测试中,依赖注入模式可以使得测试更加简单和有效。通过模拟依赖对象的行为,可以很容易地对被测试对象进行隔离和测试。
  2. 插件式开发 :在插件式开发中,依赖注入模式可以使得插件之间的依赖关系更加清晰和灵活。通过配置文件或注解等方式,可以很容易地管理和控制插件之间的依赖关系。
  3. 多环境配置 :在不同的运行环境中,可能需要使用不同的依赖对象。通过依赖注入模式,可以很容易地根据不同的环境配置来注入不同的依赖对象,从而提高了代码的灵活性和可维护性。
  4. 框架开发 :在框架开发中,依赖注入模式可以使得框架更加灵活和可扩展。通过提供统一的依赖注入机制,可以使得框架的使用者更加方便地使用和管理框架提供的各种服务。

在这里插入图片描述

依赖注入和控制反转的区别

控制反转(Inversion of Control,简称IoC)依赖注入(Dependency Injection,简称DI)是两个相关但略有不同的概念。

控制反转是创建对象实例的控制权从代码控制剥离到IoC容器控制,侧重于原理。依赖注入则是在创建对象实例时,为这个对象注入属性值或其它对象实例,侧重于实现。

简单来说,依赖注入是从应用程序的角度在描述:应用程序依赖容器创建并注入它所需要的外部资源;而控制反转是从容器的角度在描述:容器控制应用程序,由容器反向的向应用程序注入应用程序所需要的外部资源(对象、文件等)。

在这里插入图片描述

代码示例

Java实现依赖注入模式

以下是一个简单的Java实现依赖注入模式的示例:

// 定义依赖对象
public class Dependency {
    public void doSomething() {
        System.out.println("Dependency is doing something.");
    }
}

// 定义服务类,接受依赖对象
public class Service {
    private Dependency dependency;

    // 通过构造函数注入依赖对象
    public Service(Dependency dependency) {
        this.dependency = dependency;
    }

    public void performTask() {
        dependency.doSomething();
    }
}

// 定义容器类,负责创建和注入依赖对象
public class Container {
    private Map<Class<?>, Object> dependencies = new HashMap<>();

    public <T> void addDependency(Class<T> clazz, T instance) {
        dependencies.put(clazz, instance);
    }

    public Object getDependency(Class<?> clazz) {
        return dependencies.get(clazz);
    }
}

// 使用容器创建服务对象并注入依赖对象
public class Main {
    public static void main(String[] args) {
        Container container = new Container();
        Dependency dependency = new Dependency();
        container.addDependency(Dependency.class, dependency);
        Service service = new Service((Dependency) container.getDependency(Dependency.class));
        service.performTask(); // 输出 "Dependency is doing something."
    }
}

在这个示例中,我们定义了一个依赖对象Dependency和一个服务类Service,服务类通过构造函数接受依赖对象。然后我们定义了一个容器类Container,负责创建和注入依赖对象。在主程序中,我们创建了一个容器实例,将依赖对象添加到容器中,然后通过容器实例创建服务对象并注入依赖对象。最后,我们调用服务对象的performTask()方法,输出依赖对象的doSomething()方法的结果。

Python实现依赖注入模式

以下是Python实现依赖注入模式的一个示例:

# 定义依赖对象
class Dependency:
    def do_something(self):
        print("Dependency is doing something.")

# 定义服务类,接受依赖对象
class Service:
    def __init__(self, dependency):
        self.dependency = dependency

    def perform_task(self):
        self.dependency.do_something()

# 定义容器类,负责创建和注入依赖对象
class Container:
    def __init__(self):
        self.dependencies = {}

    def add_dependency(self, clazz, instance):
        self.dependencies[clazz] = instance

    def get_dependency(self, clazz):
        return self.dependencies.get(clazz)

# 使用容器创建服务对象并注入依赖对象
def main():
    container = Container()
    dependency = Dependency()
    container.add_dependency(Dependency, dependency)
    service = Service(container.get_dependency(Dependency))
    service.perform_task()  # 输出 "Dependency is doing something."

if __name__ == "__main__":
    main()

在这个示例中,我们定义了一个依赖对象Dependency和一个服务类Service。服务类通过构造函数接受依赖对象。然后我们定义了一个容器类Container,负责创建和注入依赖对象。在主程序中,我们创建了一个容器实例,将依赖对象添加到容器中,然后通过容器实例创建服务对象并注入依赖对象。最后,我们调用服务对象的perform_task()方法,输出依赖对象的do_something()方法的结果。

在这里插入图片描述

依赖注入模式在spring中的应用

在Spring框架中,依赖注入是一种核心特性,用于管理Bean之间的依赖关系。依赖注入允许在运行时动态地将依赖对象注入到Bean中,从而降低了对象之间的耦合度,提高了代码的可维护性和可测试性。

Spring提供了多种方式来实现依赖注入,包括注解和XML配置。使用注解的方式,可以在Bean的定义中添加相应的注解(如@Autowired@Resource等),来指定注入的依赖对象。而使用XML配置的方式,可以在配置文件中定义Bean之间的关系,Spring容器在启动时会解析这些配置并自动注入依赖对象。

依赖注入主要有两种方式:构造器注入和Setter注入。构造器注入是通过Bean的构造方法来注入依赖对象,而Setter注入则是通过设置器方法来注入依赖对象。在Spring中,可以通过@Autowired注解来实现构造器注入,而通过@Resource注解或XML配置来实现Setter注入。

此外,Spring还提供了@Qualifier注解来指定具体的依赖对象。当Spring容器中存在多个符合条件的对象时,可以使用@Qualifier注解来指定要注入的具体对象。

Spring中的依赖注入模式使得代码更加清晰、灵活和易于维护,是Spring框架的核心特性之一。通过依赖注入,可以有效地管理Bean之间的依赖关系,提高应用程序的可维护性和可扩展性。

在这里插入图片描述

设计模式-工厂模式

设计模式-适配器模式

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于SSM的教育管理系统

基于SSM的教育管理系统 一、系统介绍二、功能展示1.项目内容2.项目骨架3.管理员登录4.系统界面5.注册6.系统管理7.课程管理8.添加科目9.学员信息 四、其它1.其他系统实现五.获取源码 一、系统介绍 项目名称&#xff1a;基于ssm的教育管理系统 当前版本&#xff1a;V1.0.0版本…

android——自定义TextView

效果展示&#xff1a; 代码解析&#xff1a; 1、首先设置自定义属性&#xff08;res/values下新建一个attrs.xml文件&#xff09; <?xml version"1.0" encoding"utf-8"?> <resources><!-- name 自定义view的名字 CustomTextView--&…

flask文件夹列表改进版--Bug追踪

把当前文件夹下的所有文件夹和文件列出来&#xff0c;允许点击返回上层目录&#xff0c;允许点击文件夹进入下级目录并显示此文件夹内容 允许点击文件进行下载 from flask import Flask, render_template, send_file, request, redirect, url_for import osapp Flask(__name_…

51单片机(STC8)-- 串口配置及串口重定向(printf)

文章目录 STC8串口概述串口寄存器配置串口1控制寄存器SCON串口1数据寄存器SBUF串口1模式 1工作方式串口1波特率计算方式 串口注意事项串口1通信demo串口重定向 STC8串口概述 由下图可知STC8H3K64S4带有4个4个串行通信接口&#xff0c;芯片名后两位S所带的数字即代表这款芯片带…

Systemctl | 系统服务管理利器

功能介绍 systemctl 是用于管理系统服务的命令行工具&#xff0c;常用于 Linux 系统中。提供了对系统服务&#xff08;包括启动、停止、重启、启用、禁用等&#xff09;的控制&#xff0c;以及对系统单元&#xff08;units&#xff09;的操作。 语法结构 systemctl 的基本语…

burpsuite的安装与介绍

安装(挑一个你喜欢的版本安装就行) 编程环境安装指南:Java、Python 和 Burp Suite抓包工具_burpsuite和java-CSDN博客 简介 Burp Suite是一个用于攻击Web应用程序的集成平台。它集成了多种渗透测试组件,能够帮助我们更好地完成对Web应用的渗透测试和攻击,无论是自动化还…

记一次Mac端mysql重置密码

在执行mysql命令的时候&#xff0c;报如下的错误&#xff0c;表示不支持mysql命令&#xff1a; zsh: command not found: mysql 1. 先查看mysql服务是否存在 在系统偏好设置中查看&#xff1a; 2. 发现mysql服务已经在运行&#xff0c;可能因为/usr/local/bin目录下缺失mysq…

信号处理设计模式

问题 如何编写信号安全的应用程序&#xff1f; Linux 应用程序安全性讨论 场景一&#xff1a;不需要处理信号 应用程序实现单一功能&#xff0c;不需要关注信号 如&#xff1a;数据处理程序&#xff0c;文件加密程序&#xff0c;科学计算程序 场景二&#xff1a;需要处理信…

Xshell连接不上本地虚拟机中的linux处理

0、连接不上虚拟机的原因 1、本地电脑未启用VMware网络。 2、连接协议选择错误。 3、防火墙屏蔽IP。 4、虚拟机网络连接模式不是桥接模式。 1、查看本地是否启用VMware的网络 2、连接协议选择 我们在新建会话时&#xff0c;可选的协议有FTP和SFTP两种&#xff0c;其中FTP采用21…

uniapp 手持弹幕全端实现(微信/QQ小程序 + APP)

见下述效果图,本文话少纯干货 代码实现 <template><view class="main"

【RocketMQ笔记02】安装RocketMQ可视化工具rocketmq-dashboard

这篇文章&#xff0c;主要介绍如何安装RocketMQ可视化工具rocketmq-dashboard。 目录 一、RocketMQ可视化界面 1.1、下载rocketmq-dashboard 1.2、修改配置文件 1.3、打包工程 1.4、启动rocketmq-dashboard 一、RocketMQ可视化界面 1.1、下载rocketmq-dashboard rocketm…

NET中使用Identity+CodeFirst+Jwt实现登录、鉴权

目录 前言 一、创建上下文类 1.自定义MyContext上下文类继承IdentityDbContext 2.在Program中添加AddDbContext服务 二、使用Migration数据迁移 1.在控制台中 依次使用add-migration 、updatebase 命令 2.如何修改表名 3.如何自定义字段 三、使用Identity实现登录、修改密码 …

汽车零配件装配产线中使用RFID技术和不使用RFID技术的优缺点

汽车零配件装配产线中使用RFID技术和不使用RFID技术的优缺点 RFID(射频识别技术)是非接触式自动识别技术&#xff0c;经常被使用于工业制造、物流管理、仓储物品盘点等领域。我们聊一聊在汽车零配件装配产线中使用和不使用RFID技术的优缺点 在汽车零配件装配线使用RFID技术可以…

「GPT」G、P、T分别是啥意思?

G意为Generative &#xff1a;生成式 比如&#xff0c;生成式的分类器&#xff08;模型&#xff09;包括---- generative classifiers: naive Bayes classifier and linear discriminant analysis 与之对应的为判别式----- discriminative model: logistic regression P意为…

每日一题——LeetCode206.反转链表

个人主页&#xff1a;白日依山璟 专栏&#xff1a;Java|数据结构与算法|每日一题 文章目录 1. 题目描述示例1示例2示例3提示 2. 思路3.代码 1. 题目描述 给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 示例1 输入&#xff1a;head [1…

讯飞星火认知大模型智能语音交互调用

随着国内外大模型热度的兴起&#xff0c;依托于大模型的智能化&#xff0c;传统的人机交互已经不能满足人们交互的需求。而结合语音和大模型的交互拜托传统互联网获取知识的文字限制&#xff0c;用语音也可以轻松获取想要的知识和思路。 一、大模型智能语音交互调用实现思路 …

nginx-proxy-manager初次登录502 bad gateway

nginx-proxy-manager初次登录502 bad gateway 按照官方docker-compose安装后,页面如下: 默认账户密码: adminexample.com/changeme点击sign in,提示Bad Gateway 打开调试 重装后依然如此,最后查阅githup issue 找到答案 https://github.com/NginxProxyManager/nginx-proxy-…

16.Redis 高级数据类型 + 网站数据统计

目录 1.Redis 高级数据类型 2.网站数据统计 2.1 业务层 2.2 表现层 2.2.1 记录数据 2.2.2 查看数据 1.Redis 高级数据类型 HyperLogLog&#xff1a;采用一种基数算法&#xff0c;用于完成独立总数的统计&#xff1b;占据空间小&#xff0c;无论统计多少个数据&#xff0…

Oraclelinux部署Oracle服务

采用图形化界面 user用户 oracle用户 #清屏 clear #设置主机名 hostnamectl set-hostname ceshidb sed -i 1,2 s/^/#/ /etc/hosts echo "127.0.0.1 ceshidb" >> /etc/hosts echo "::1 ceshidb" >> /etc/hosts ping -c 5…

STM32F4系列单片机库函数模板工程创建

目录 一、工程配置 1、新建工程 2、芯片选择 3、工程子文件夹创建 &#xff08;1&#xff09;FWLIB文件夹添加文件 &#xff08;2&#xff09;CORE文件夹添加文件 &#xff08;3&#xff09;USER文件夹添加文件 4、工程设置 &#xff08;1&#xff09;工程中添加文件夹…