Spring核心之一:IOC

2023-11-12

    IOC(Inversion of Control)其实是一种思想,这种思想并不是Spring独有的,而是在软件开发中,大家提出的一种开发原则,类似面向接口编程原则、开闭原则等。

    网上有很多类似的文章尝试去通俗易懂地解释IOC思想,这里我根据自己的理解尝试去解释一下这个概念,看下面这个类:

public class Car {
    private Wheel wheel;
    /**
     * Car类的run方法,其实是需要调用Wheel的turn方法来完成
     * 汽车的奔跑是依赖轮子的转动
     */
    public void run(){
        wheel.trun();
    }
}
public interface Wheel {
    void trun();
}

Car类run()方法的执行,是依赖另外一个接口Wheel,这里肯定有小伙伴问,为什么Wheel是定义成一个接口呢?这其实是我们Java编程的另外一个原则的体现——面向接口编程。run()方法的内容,并不关心是什么轮子来转动,只知道轮子能转就行,至于是前驱轮子转、后驱轮子转,还是前后驱都转,Car类并不关心。换句话说,Wheel接口的实现类是什么,Car类并不关心,所以没有必要在Car类中定义具体的实现,只需要定义一个Wheel接口就可以了。

现在想要实现面向接口编程我们只差Wheel接口的实现类了:

/**
 * 前驱轮的实现
 */
public class PrecursorWheel implements Wheel{
    @Override
    public void trun() {
        System.out.println("precursor trun!");
    }
}

我们新建了一个 Wheel接口 的实现类PrecursorWheel。但是这样很明显还不够,因为目前Car 类的 wheel成员变量还是个空引用,并没有关联PrecursorWheel的实现类呢。于是我们第一反应是这样改代码:

public class Car {
    private Wheel wheel;
    /**
     * Car类的run方法,其实是需要调用Wheel的turn方法来完成
     * 汽车的奔跑是依赖轮子的转动
     */
    public void run(){
        wheel = new PrecursorWheel();//wheel指向PrecursorWheel前驱轮实现类
        wheel.trun();
    }
}

然后我们可以实例化一个Car类,然后让Car真正跑起来了,写个测试类(main方法就行)测一下:

public static void main(String[] args) {
        Car car = new Car();
        car.run();
}

测试结果就不贴了,Java新手脑补也能知道,But,如果这时候,客户说我不想要 前驱的车了,我要个后驱的车,咋办咧?简单!增加一个实现类:
 

/**
 * 后驱轮子的实现类
 */
public class RearWheel implements Wheel{
    @Override
    public void trun() {
        System.out.println("rear trun!");
    }
}

然后改造Car类:

public class Car {
    private Wheel wheel;

    /**
     * Car类的run方法,其实是需要调用Wheel的turn方法来完成
     * 汽车的奔跑是依赖轮子的转动
     */
    public void run(){
        wheel = new RearWheel();wheel指向RearWheel后驱轮实现类
        wheel.trun();
    }

    public static void main(String[] args) {
        Car car = new Car();
        car.run();
    }
}

这样Car类的实例,就变成了后轮驱动的Car对象了。
上面的编码风格用其特点就是如下:

目标类(Car类)中直接实例化其依赖接口的实现类(RearWheel、PrecursorWheel);

虽然我们的例子中只有 Car类依赖Wheel接口,但以后可能会有Truck类、Bicycle类....等很多类依赖Wheel接口,Wheel接口的实现类有一点点变动,依赖于它的类都要相应修改,这是牵一发而动全身的修改。

显然,问题就出在  Car 类中  这句代码上:wheel = new RearWheel();

这种硬编码的方式,让Car类与RearWheel类耦合了。

那么如何处理这样讨人厌的代码呢?大家就说,那就在程序种单独找一个第三方来管理类似这种wheel = new RearWheel()代码吧,这种思想就叫 IOC。

抽象总结出来就是:某一接口(如Wheel接口)具体实现类的选择权,从目标依赖类(如Car类)中移除,交由第三方来完成。这种思想就称为 IOC。 本例子中实现如下:

新建一个第三方类WheelManager,来专门管理 Wheel接口的实现类实例,所有与Wheel接口依赖的类,都通过第三方来得到想要的实例:

public class WheelManager {
    public static Wheel acquireWheel(String name){
        if("rear".equals(name)){
            return new RearWheel();
        }
        return new PrecursorWheel();
    }
}

Car类改造:

public class Car {
    private Wheel wheel;
    /**
     * Car类的run方法,其实是需要调用Wheel的turn方法来完成
     * 汽车的奔跑是依赖轮子的转动
     */
    public void run(){
        wheel = WheelManager.acquireWheel("rear");
        wheel.trun();
    }
}

如果还有 Truck类、Bicycle类,也类似:

public class Truck {
    private Wheel wheel;
    public void truckRun(){
        wheel = WheelManager.acquireWheel("");
        wheel.trun();
    }
}
public class Bicycle {
    private Wheel wheel;
    public void bicycleRun(){
        wheel = WheelManager.acquireWheel("rear");
        wheel.trun();
    }
}

上述就是一种简单的 IOC思想(控制反转)的实现方式:WheelManager变成了轮子的管理中心,所有Wheel接口的实现类实例,都交由它来管理。Car、Truck、Bicycle等具体的业务类,都通过WheelManager间接来与其要依赖的类进行耦合。

对控制反转的理解:
控制:指定Car类的Wheel成员变量是Wheel接口哪个实现类的实例,这个控制权。
反转:上述的控制权,不在Car类定义中去指定,而是交由第三方(WheelManager)来决定。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring核心之一:IOC 的相关文章

随机推荐

  • openwrt reboot流程

    openwrt 系统中 当执行了 reboot 命令 系统将会发生什么事情呢 如何进行重启的呢 下面来一起看一下 reboot 应用层操作 首先 reboot 是由busybox 它是一个集成了常用Linux命令和工具的软件 提供的一个Li
  • leetcode算法面试题:串联所有单词的子串问题、单词拆分问题

    串联所有单词的子串问题 给定一个字符串 s 和一些 长度相同 的单词 words 找出 s 中恰好可以由 words 中所有单词串联形成的子串的起始位置 注意子串要与 words 中的单词完全匹配 中间不能有其他字符 但不需要考虑 word
  • 数据挖掘算法基础-关联规则

    数据挖掘中 被常拿来说的啤酒尿布的例子就是一个很典型的运用关联算法来做购物来分析的例子 常被用于交易数据 关系数据的分析 发现数据集中隐藏的频繁模式 这些频繁模式可以用关联规则的形式表示 有效的关联规则对商家的商品进出货摆放都有很大的指导意
  • 直方图均衡化与直方图规定化

    一 认识图像 当我们面对图像的时候 我们面对的是抽象的矩阵 如下图 下面是0 255的灰度图像的表示 密密麻麻的 那么我们做的直方图 其实就是对这些像素值的统计 如下图所示 其中Bin表示条数 数据和范围是对图的解释 二 为什么要做直方图均
  • qt 嵌入web页面_Qt -在应用程序中嵌入Web内容之环境搭建

    一 Qt应用程序与Web结合的发展 1 从Qt5 5开始 Qt WebKit模块被废弃了 取而代之的是Qt WebEngine模块 当时可以使用该模块将应用程序与Web技术结合 2 Qt WebEngine模块提供了一个Web浏览器引擎 可
  • ChatGPT:概述Vue.js中data函数初始化和created钩子函数调用的顺序和问题解决方法

    ChatGPT 概述Vue js中data函数初始化和created钩子函数调用的顺序和问题解决方法 我将输入一段Vue代码 请你记住 created console log this queryInfo this getClueList
  • Libuv源码分析 —— 6. 事件循环【uv_run】

    通过之前的学习 咱们已经明白了在事件循环中的三个核心内容 分别是 Libuv源码分析 定时器 Libuv源码分析 idle prepare check Libuv源码分析 poll io 现在让咱们从头捋一遍事件循环到底完成了什么功能呢 u
  • scrapy里面的response.xpath(“用xpath插件找打的路径“)返回值为空?

    response xpath 用xpath插件找打的路径 返回值为空 1 可能是因为路径是有问题的 2 可能是start urls的路径是有问题的 可以从network中找找路径 复制一下
  • 使用vant2问题整理

    1 export createVNode imported as createVNode was not found in vue possible exports EffectScope computed customRef defaul
  • C++11移动语义解析

    当给函数传递对象当做函数参数时 可以使用引用类型来减少拷贝对象的代价 尤其是避免容器的拷贝等 但是当把函数内的局部对象当做返回值时 我们无法返回该局部对象的引用 导致每次返回局部对象都会进行拷贝 因为返回局部对象的引用是无意义的 当函数调用
  • 编译原理实验日志

    编译原理 生成四元式 实验原理 构造SLR 1 分析表 调试过程 实验原理 构造SLR 1 分析表 首先求得follow集 follow E follow T follow F 画出DFA状态转换图 调试过程 没有判断 因为字符串中没有表示
  • dubbo优雅停机

    dubbo优雅停机 Dubbo是通过JDK的ShutdownHook来完成优雅停机的 所以如果用户使用 kill 9 PID 等强制关闭指令 是不会执行优雅停机的 只有通过 kill PID 时 才会执行 原理 服务提供方 停止时 先标记为
  • grafana与prometheus实现监控可视化

    1 Grafana基础知识 Grafana是一个开源的指标监测和可视化工具 官方网站为 Grafana The open observability platform Grafana Labs 常用于展示基础设施的时序数据和应用程序运行分析
  • 大话设计模式9—观察者模式(通知者与观察者)

    大话设计模式9 观察者模式 老板回来 我不知道 1 需求 老板回来 我不知道 2 双向耦合的设计 2 1 前台秘书类 2 2 看股票同事类 2 3main函数及输出 3 解耦修改 3 1 抽象观察者类 3 2 前台秘书类 3 3 main函
  • Java编程中出现乱码的原因

    乱码的原因 理解了编码 我们来看乱码 乱码有两种常见原因 一种比较简单 就是简单的解析错误 另外一种比较复杂 在错误解析的基础上进行了编码转换 我们分别介绍 1 解析错误 看个简单的例子 一个法国人采用Windows 1252编码写了个文件
  • Windows/PC(win + R) 电脑常见操作命令50条

    摘要 win R 1 cmd 打开终端 2 gpedit msc 本地组策略编辑器 3 Nslookup IP地址侦测器 4 explorer 文件资源管理器 5 notepad 系统默认记事本 6 cleanmgr 磁盘清理 7 serv
  • 微信公众号运营错误的四个方式

    1 很多广告宣传 很多的微信公众平台注册便是为了更好地宣传策划商品 在开展內容輸出的情况下 沒有立在客户的视角开展內容輸出 消息推送的內容可能是七拼八凑 与微信公众号的精准定位偏移很远 要想取得成功的运营公众号 最先要做的便是深层次发掘总体
  • vue3 + vite 在线预览docx, pdf, pptx(内外网)并实现移动端适配

    一 内网 1 docx 使用docx preview 安装插件 npm i docx preview S 引入依赖 docx import renderAsync from docx preview let docx import meta
  • GO终端读取

    GO终端读取 Go语言获取标准输入 Go语言 fmt 包下有 fmt Scan fmt Scanf fmt Scanln 三个函数 可以在程序运行过程中获取用户输入 func Scan a interface n int err error
  • Spring核心之一:IOC

    IOC Inversion of Control 其实是一种思想 这种思想并不是Spring独有的 而是在软件开发中 大家提出的一种开发原则 类似面向接口编程原则 开闭原则等 网上有很多类似的文章尝试去通俗易懂地解释IOC思想 这里我根据自