理解依赖注入(DI - Dependency Injection)
系列教程
- Spring 框架介绍
- Spring 框架模块
- Spring开发环境搭建(Eclipse)
- 创建一个简单的Spring应用
- Spring 控制反转容器(Inversion of Control – IOC)
- 理解依赖注入(DI – Dependency Injection)
- Bean XML 配置(1)- 通过XML配置加载Bean
- Bean XML 配置(2)- Bean作用域与生命周期回调方法配置
- Bean XML 配置(3)- 依赖注入配置
- Bean XML 配置(4)- 自动装配
- Bean 注解(Annotation)配置(1)- 通过注解加载Bean
- Bean 注解(Annotation)配置(2)- Bean作用域与生命周期回调方法配置
- Bean 注解(Annotation)配置(3)- 依赖注入配置
- Bean Java配置
- Spring 面向切面编程(AOP)
- Spring 事件(1)- 内置事件
- Spring 事件(2)- 自定义事件
依赖注入(Dependency Injection, DI)是一种设计模式,也是Spring框架的核心概念之一。其作用是去除Java类之间的依赖关系,实现松耦合,以便于开发测试。为了更好地理解DI,先了解DI要解决的问题。
耦合太紧的问题
如果使用一个类,自然的做法是创建一个类的实例:
class Player{
Weapon weapon;
Player(){
// 与 Sword类紧密耦合
this.weapon = new Sword();
}
public void attack() {
weapon.attack();
}
}
这个方法存在耦合太紧的问题,例如,玩家的武器只能是剑Sword
,而不能把Sword
替换成枪Gun
。要把Sword
改为Gun
,所有涉及到的代码都要修改,当然在代码规模小的时候这根本就不是什么问题,但代码规模很大时,就会费时费力了。
依赖注入
依赖注入是一种消除类之间依赖关系的设计模式。例如,A类要依赖B类,A类不再直接创建B类,而是把这种依赖关系配置在外部xml文件(或java config文件)中,然后由Spring容器根据配置信息创建、管理bean类。
示例:
class Player{
Weapon weapon;
// weapon 被注入进来
Player(Weapon weapon){
this.weapon = weapon;
}
public void attack() {
weapon.attack();
}
public void setWeapon(Weapon weapon){
this.weapon = weapon;
}
}
如上所示,Weapon
类的实例并不在代码中创建,而是外部通过构造函数传入,传入类型是父类Weapon
,所以传入的对象类型可以是任何Weapon
子类。
传入哪个子类,可以在外部xml文件(或者java config文件)中配置,Spring容器根据配置信息创建所需子类实例,并注入Player
类中,如下所示:
<bean id="player" class="com.qikegu.demo.Player">
<construct-arg ref="weapon"/>
</bean>
<bean id="weapon" class="com.qikegu.demo.Gun">
</bean>
上面代码中<construct-arg ref="weapon"/>
ref指向id="weapon"
的bean,传入的武器类型是Gun
,如果想改为Sword
,可以作如下修改:
<bean id="weapon" class="com.qikegu.demo.Sword">
</bean>
只需修改这一处配置就可以。
松耦合,并不是不要耦合。A类依赖B类,A类和B类之间存在紧密耦合,如果把依赖关系变为A类依赖B的父类B0类,在A类与B0类的依赖关系下,A类可使用B0类的任意子类,A类与B0类的子类之间的依赖关系是松耦合的。
可以看到依赖注入的技术基础是多态机制与反射机制。
原文地址:https://www.cnblogs.com/haibianren/p/11642309.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- flink教程-基于flink 1.11 使 sql客户端支持执行sql文件
- flink教程-详解flink 1.11 中的JDBC Catalog
- flink教程-flink modules详解之使用hive函数
- 面试iOS 机会在自己手中
- Flink教程-将流式数据写入redis
- Flink教程-keyby 窗口数据倾斜的优化
- Flink源码分析之深度解读流式数据写入hive
- 浙大版《C语言程序设计(第3版)》题目集 习题10-1 判断满足条件的三位数
- 差分标记-HDU1556 Color the ball
- flink cep 案例之机架温度监控报警
- 详解flink 1.11中的新部署模式-Application模式
- 浙大版《C语言程序设计(第3版)》题目集 习题10-2 递归求阶乘和
- hadoop源码解析之RPC分析
- 存储过程和触发器
- hadoop源码学习之namenode启动