• Spring学习笔记(二)Spring的控制反转(设计原则)与依赖注入(设计模式)


    一、控制反转:缩写IoC

    是一种设计原则,降低程序代码之间的耦合度

    对象由Ioc容器统一管理,当程序需要使用对象时直接从IoC容器中获取。这样对象的控制权就从应用程序转移到了IoC容器

    二、依赖注入:缩写DI

    依赖注入是一种消除类之间依赖关系的设计模式。例如,A类要依赖B类,A类不再直接创建B类,而是把这种依赖关系配置在外部xml文件(或java config文件)中,然后由Spring容器根据配置信息创建、管理bean类。可以简单的理解为给对象赋值

    两种实现方式:

    1、构造方法注入(非主流了解即可)

    Spring容器调用构造方法注入被依赖的实例,构造方法可以是有参的或者是无参的。Spring在读取配置信息后,会通过反射方式调用实例的构造方法,如果是有参构造方法,可以在构造方法中传入所需的参数值,最后创建类对象。

    步骤:

    编写用户类User类,在User类中定义id、name和password三个属性

    创建applicationContext-User.xml文件,在该文件中添加User类的配置信息

    编写测试类:创建测试类TestUser,用于测试依赖注入的结果

    编写用户类User类

    1. public class User {
    2. private int id; private String name; private String password;
    3. public User(int id, String name, String password){
    4. this.id=id; this.name=name; this.password=password; }
    5. public String toString(){
    6. return "id="+id+",name="+name+",password="+password; }}

    配置信息中使用到元素

    具体介绍如下:

    一个元素表示构造方法的一个参数,且定义时不区分顺序,只需要通过元素的name属性指定参数即可。元素还提供了type属性类指定参数的类型,避免字符串和基本数据类型的混淆。

    例如:

           

           

           

           

           

    测试类代码

    public class TestUser {

        public static void main(String[] args)throws Exception{

            //加载applicationContext.xml配置

            ApplicationContext applicationContext=new

            ClassPathXmlApplicationContext("applicationContext-User.xml");

            //获取配置中的User实例

            User user=( User)applicationContext.getBean("user");

            System.out.println(user);

        }

    }

    2、属性setter方法注入(主流注入方法)

    步骤

    编写用户类User类,在User类中定义id、name和password三个属性并且注明setter方法

    创建applicationContext-User.xml文件,在该文件中添加User类的配置信息

    编写测试类:创建测试类TestUser,用于测试依赖注入的结果

     编写用户类User类

    1. public class User {
    2. private int id;
    3. private String name;
    4. private String password;
    5. public void setId(Integer id){
    6. this.id=id;
    7. }
    8. public void setUsername(String username){
    9. this.username= username;
    10. }
    11. public void setPassword (String password){
    12. this. password = password;
    13. }
    14. public String toString(){
    15. return "id="+id+",name="+name+",password="+password; }
    16. }

    创建applicationContext-User.xml文件,在该文件中添加User类的配置信息,

    在类中注明setter方法,在配置文件中使用property(属性的意思)元素

    1. <bean id="user" class="com.itheima.User">
    2. <property name="id" value="2">property>
    3. <property name="name" value="李四">property>
    4. <property name="password" value="456">property>
    5. bean>

    property属性使用

    name的属性值准确的讲不是属性名,而是set方法去掉set关键字后的名字

    属性名idàsetter方法setIdd();去掉关键字setà即idd(驼峰命名)

    测试类:

    1. public class TestUser {
    2.     public static void main(String[] args)throws Exception{
    3.         //加载applicationContext.xml配置
    4.         ApplicationContext applicationContext=new
    5.         ClassPathXmlApplicationContext("applicationContext-User.xml");
    6.         //获取配置中的User实例
    7.         User user=( User)applicationContext.getBean("user");
    8.         System.out.println(user);
    9.     }
    10. }

    三、依赖注入和控制反转的比较

    依赖注入(DI)和控制反转(IoC)是从不同角度来描述了同一件事情

    依赖注入是从应用程序的角度描述,即应用程序依赖IoC容器创建并注入它所需要的外部资源;而控制反转是从IoC容器的角度描述,即IoC容器控制应用程序,由IoC容器反向地向应用程序注入应用程序所需要的外部资源。这里所说的外部资源可以是外部实例对象,也可以是外部文件对象等。

    四、对降低程序代码之间的耦合度的解释:

    在传统模式中如果使用一个类,自然的做法是创建一个类的实例:

    1. class Player
    2.     Weapon weapon; 
    3.     Player(){ 
    4.         // 与 Sword类紧密耦合
    5.         this.weapon = new Sword(); 
    6.     } 
    7.     public void attack() {
    8.         weapon.attack();
    9.     }
    10. }  

    这个方法存在耦合太紧的问题,例如,玩家的武器只能是剑Sword而不能把Sword替换成枪Gun。要把Sword改为Gun,所有涉及到的代码都要修改,当然在代码规模小的时候这根本就不是什么问题,但代码规模很大时,就会费时费力了。

    运用依赖注入的方式降低耦合的示例:

    1. class Player
    2.     Weapon weapon; 
    3.     // weapon 被注入进来
    4.     Player(Weapon weapon){ 
    5.         this.weapon = weapon; 
    6.     } 
    7.     public void attack() {
    8.         weapon.attack();
    9.     }
    10.     public void setWeapon(Weapon weapon)
    11.         this.weapon = weapon; 
    12.     } 
    13. }  

    如上所示,Weapon类的实例并不在代码中创建,而是外部通过构造函数传入,传入类型是父类Weapon,所以传入的对象类型可以是任何Weapon子类。

    传入哪个子类,可以在外部xml文件(或者java config文件)中配置,Spring容器根据配置信息创建所需子类实例,并注入Player类中,如下所示:

    1.     <bean id="player" class="com.Springyx.demo.Player">
    2.         <construct-arg ref="weapon"/>
    3.     bean>
    4.     
    5.     <bean id="weapon" class=" com.Springyx.demo.Gun">
    6.     bean>

    上面代码中 ref指向id="weapon"的bean,传入的武器类型是Gun,如果想改为Sword,可以作如下修改:

       

       

    只需修改这一处配置就可以。

    注意:松耦合,并不是不要耦合。A类依赖B类,A类和B类之间存在紧密耦合,如果把依赖关系变为A类依赖B的父类B0类,在A类与B0类的依赖关系下,A类可使用B0类的任意子类,A类与B0类的子类之间的依赖关系是松耦合的(即创建中间商)

  • 相关阅读:
    react-grapesjs——开源代码学习与修改(初出茅庐)
    [CVPR2022] A Dual Weighting Label Assignment Scheme for Object Detection
    typescript声明文件学习笔记
    windows命令行XCOPY命令
    vue3+ele-plus+sortableJs对el-table使用sortableJs插件对表格拖拽时限定某列或某行不允许拖拽
    SpringSecurity基础概念和案例代码
    IDEA操作Sharding-JDBC实战2
    【vue3】实现筛选页组件(深层嵌套循环数据切换)的封装和调用
    机器学习笔记 - 特斯拉的占用网络简述
    uni-app —— uni-app的生命周期
  • 原文地址:https://blog.csdn.net/weixin_72154059/article/details/136134242