首页 > 其他分享 >什么是依赖注入(DI)和控制反转(IOC)

什么是依赖注入(DI)和控制反转(IOC)

时间:2024-10-27 16:00:44浏览次数:1  
标签:依赖 DI 对象 反转 Weapon Player IOC weapon 注入

介绍

依赖注入,Dependency Injection。
在说明依赖注入之前,我们先描述一个场景。

玩家类依赖于武器进行攻击。
在传统的编程逻辑中,代码如下。可以看到,Player玩家不仅依赖于Weapon,而且还依赖于Sword。而且可以预见的是,假如Sword剑换成枪Spear,需要重新创建一个玩家类,这会导致大量的重复代码,不仅编写时麻烦,修改时还容易忘记改。

class Player {
    Weapon weapon;
    Player() {
        this.weapon = new Sword();  // 直接创建Sword对象,耦合度较高
    }
    public void attack() {
        weapon.attack();
    }
}

依赖注入

class Player {
    Weapon weapon;
    Player(Weapon weapon) {
        this.weapon = weapon;  // 通过构造函数注入Weapon对象
    }
    public void attack() {
        weapon.attack();
    }
}

以上的方法就是依赖注入,其核心思想就是:将类的实例化延迟到用户使用时。
可以看到,Player现在仅依赖一个Weapon类,而使用不同的武器只要继承Weapon并传入Player就可以了。

现在,我们再回到“依赖注入”这个名词方面,“依赖”,指的是作为参数被传入方法中的对象,比如在上面的例子中,我们可以把Sword的对象传给Player构造函数。而“注入”则代表这个Sword对象(叫做依赖)被注入给了Player对象。所以依赖注入是把一个对象注入给另一个对象。

Player player = new Player(new Sword());
// 假如换成枪/矛
Player player = new Player(new Spear());

不难发现,“依赖注入”所做的事情,就是把依赖的创建延迟到外部。

控制反转(IoC)

Inversion of Control,直译“控制反转”。
依赖注入说了半天,原来只是用了一下多态,那为啥我还是看不懂Spring呢?这就不得不说IoC了。

控制反转的意思就是将对象或程序部分的控制权转移到容器或框架中。而一般来说,都是对象创建的过程移交给了容器,比如Spring容器。到这里两个词其实都解释明白了。

以Spring的Autowired为例

在Spring中,获取对象自不必说,使用@Component等注解就可以把该类交给Spring容器控制(控制反转)。而Autowired自动装配就是用来注入依赖的。

public interface Weapon {
    void attack();
}

@Component
public class Sword implements Weapon {
    @Override
    public void attack() {
        System.out.println("Swinging a sword!");
    }
}
@Component
public class Player {

    // 使用@Autowired注解自动注入Weapon类型的依赖
    @Autowired
    private Weapon weapon;

    public void fight() {
        weapon.attack();
    }
}

以上代码实现的功能是一样的,一位拿着剑的玩家
那么其实很让人疑惑,Autowired或者说控制反转的优势在哪里呢?
假如我们需要一位拿着枪/矛的玩家,我们可以这样修改:

@Component("mySpear")
public class Spear implements Weapon {
    // ...
}

@Autowired
@Qualifier("mySpear")
private Weapon weapon;

可能有人已经发现了,Spring的控制反转,更注重一个对象的创建,而不是类本身。而Java不能单独创建对象,只能创建类。通过以上的例子,我们既可以创建一个拿着剑的玩家,也可以创建一个拿着枪的玩家,而Spring Bean的大多数情况下,一个类只有一个实例(所以Autowired非常好用)。我们要创建一个拿着不同武器的玩家,不需要写一个新的Player类,也不需要new Player(new Spear());,而只需要修改注解即可,因为我们实际上只关心一个Player对象而不是两个或者更多。

这个例子举得不是很好,但是我想说的就是Spring的依赖注入让我们更像是在编写一个对象,而不是一个类,他让我们把对象的信息写到了类中,并自动实例化放到容器里,我们可以通过Autowired等方式获取这个对象并直接使用,而不是到使用时才去实例化这个对象。这样的好处在于,使用某个对象时,代码将非常精简;当我们想要让玩家换武器时,只需要新写一个武器,修改一下注入即可,测试起来很方便,而且由于是依赖接口的(而非具体实例),因此相对稳定,如果修改后出现问题,多半是新的武器写得有问题。

标签:依赖,DI,对象,反转,Weapon,Player,IOC,weapon,注入
From: https://www.cnblogs.com/oldsaltfish/p/18508519

相关文章

  • 【0x0040】HCI_LE_Set_Periodic_Advertising_Enable命令全面解析
    目录一、命令概述1.1.命令执行条件1.2.限制条件1.3.注意事项  二、命令格式2.1. HCI_LE_Set_Periodic_Advertising_Enable命令格式2.2.HCICommandComplete(响应事件)格式三、命令参数详细说明3.1.Enable3.2.Advertising_Handle四、返回参数详细说明五......
  • Java NIO direct buffer的优势在哪儿
    JavaNIODirectBuffer的优势主要体现在:减少数据在Java堆和本地堆之间的复制次数、提高了内存管理效率、可直接访问操作系统的内存资源、增加了处理大型数据集的能力。这些优势共同作用,显著提高了大数据量传输的性能。其中,提高内存管理效率尤为关键,因为它减轻了垃圾收集器的压力......
  • 2024年最新互联网大厂精选 Java 面试真题集锦(JVM、多线程、MQ、MyBatis、MySQL、Redis
    前言春招,秋招,社招,我们Java程序员的面试之路,是挺难的,过了HR,还得被技术面,在去各个厂面试的时候,经常是通宵睡不着觉,头发都脱了一大把,还好最终侥幸能够入职一个独角兽公司,安稳从事喜欢的工作至今...近期也算是抽取出大部分休息的时间,为大家准备了一份通往大厂面试的小捷径,准备......
  • Coding和Github有什么区别
    Coding和Github的区别主要体现在:1.来源和发展背景不同;2.功能特性不同;3.使用者群体不同;4.可用资源不同;5.服务区域和语言支持不同。总的来说,Coding更侧重于团队协作和项目管理,有更多针对中国市场的本土化服务,而Github作为全球最大的开源社区,拥有丰富的开源项目和全球开发者的交流环......
  • Diffusion Probabilistic Models for 3D Point Cloud Generation——点云论文阅读(8)
    此内容是论文总结,重点看思路!!文章概述该文献介绍了一种用于3D点云生成的概率模型。点云是表示3D物体和场景的常用方式,但由于其不规则的采样模式,与图像相比,点云生成更具挑战性。现有方法如GANs、流模型和自回归模型在点云生成方面取得了进展,但它们在训练稳定性、生成顺序假设和......
  • 【Motion Forecasting】SmartRefine:A Scenario-Adaptive Refinement Framework for Mo
    SmartRefine:AScenario-AdaptiveRefinementFrameworkforEfficientMotionPrediction今天要分享的文章来自于商汤科技在CVPR2024发表的文章SmartRefine,这是一项关注于双阶段轨迹解码器的改进工作。Abstract预测自动驾驶车辆周围智能体的未来运动对于自动驾驶车辆......
  • Windows 10上编译FFmpeg以支持NVIDIA GPU加速
    目录一、引言二、使用NVDIA加速的准备工作三、编译FFmpeg四、使用FFmpeg五、常见问题及解决方案六、总结一、引言        FFmpeg是一个强大的多媒体处理工具,它支持音频、视频和流媒体的录制、转换和流式传输。NVIDIAGPU提供了强大的计算能力,通过CUDA和NVENC......
  • Linux驱动开发 内核时间管理 内核定时器使用 以及 从 应用层通过ioctl接口控制内核定
    Linux内核时间管理以及内核定时器使用在Linux驱动开发中,内核时间管理和内核定时器是用于管理时间和调度任务的重要工具。内核定时器允许开发者在指定的时间间隔内执行某些任务,而内核时间管理则提供了时间相关的功能,如获取当前时间、时间延迟等。1.内核时间管理内核......
  • NVIDIA 发布适用于网络安全的 NIM Blueprint
    德勤使用适用于容器安全的NVIDIANIMAgentBlueprint帮助企业利用开源软件构建安全的AI。文章目录......
  • 10.26 吃 Div.2 水分
    10.26CodeforcesRound982(Div.2)Solve:A~D2(4/5)Rank:24Rating:\(2098+114=2212\)Pref:2554发挥评价:Good-果然还是Div.2善良啊!()随便做了前四道,没咋卡住,就这名次了,可惜C有一发罚时吃得不温不火,比较可惜。然后E1咋这么难。CF2027D1/D2长为\(n\)的序......