zoukankan      html  css  js  c++  java
  • 剖析DI

    0x00.前言

    当我们研究一些晦涩的源码,上网查阅资料的时候,映入眼帘的总有这么些名词:DIP、IOC、DI、DL、IOC容器这些专业名词。如果不懂这些名词背后的含义,我们内心有可能是这样的:
    image

    0x01.小例子

    /**
     * 餐厅类
     */
    public class Restaurant {
    
        //后台收银系统
        private WeChatPay pay = new WeChatPay();
    
        //收款操作
        public void transact(double money) {
            pay.receiveMoney(money);
        }
    }
    
    
    import java.util.Date;
    
    /**
     * 微信
     */
    public class WeChatPay {
        public void receiveMoney(double money) {
            System.out.println(new Date() + ",已用微信收款:" + money + "元");
        }
    }
    
    

    image

    这时候Restaurant类就依赖于WeChatPay,两个类产生依赖
    

    0x02.DIP

    DIP的英文名:Dependency Inversion Principle,中文名:依赖倒转原则

    定义:

    • High-level modules should not depend on low-level modules. Both should depend on abstractions

    • Abstractions should not depend on details. Details should depend on abstractions

    理解:

    • 高层模块不应该直接依赖于底层模块的具体实现,而应该依赖于底层的抽象。换言之,模块间的依赖是通过抽象发生,实现类之间的不发生直接依赖关系,其依赖关系是通过接口或抽象类产生的

    • 面向接口编程

    它仅仅是面向对象软件设计的一种原则。它仅仅告诉你两个模块之间如何协调依赖关系,但是并没有告诉你如何做!

    举个例子

    我们经常所说的三层架构(UI、BLL、DAL)
    image

    image

    图二的版本,就是高层模块依赖于低层模块的抽象,就好像依赖“倒置”。这样可以使得整体的架构更加的稳定,灵活,及自如的面对需求的变化。

    0x03.IOC

    • IOC的英文名:Inversion Of Control ,中文名:控制反转
    • IOC基于DIP原则上的实现的是一种软件设计模式,它告诉你应该如何做,来解除相互依赖模块的耦合。它为相互依赖的组件提供抽象,将依赖对象的获得交给第三方来控制,即依赖对象不在被依赖的类中直接通过new来获取。
    • IOC的实现的方式一般有两种,依赖注入和依赖查找。一般DI使用的比较多

    0x04.DI

    • DI的英文名:Dependency Injection,中文名称:依赖注入。
    • DI就是将依赖对象的创建和绑定转移到被依赖对象类的外部来实现。它提供是一种机制,将需要依赖(低层模块)对象的引用传递给被依赖(高层模块)对象。

    DI注入有三种方式

    • 构造函数注入
    • 属性注入
    • 接口注入

    Demo讲解

    /**
     * di Ipay 接口
     */
    public interface IPay {
        void receiveMoney(double money);
    }
    
    
    /**
     * 重构后的微信支付
     */
    public class WebChatPay implements IPay {
        public void receiveMoney(double money) {
            Date now = new Date();
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            System.out.println(format.format(now) + ",已用重构后的微信收款:" + money + "元");
        }
    }
    
    /**
     * 重构后的餐厅类构造器注入
     */
    public class Restaurant {
    
        private IPay _pay;
    
        public Restaurant(IPay pay) {
            this._pay = pay;
        }
    
        //收款操作
        public void transact(double money) {
            _pay.receiveMoney(money);
        }
    }
    
    

    0x01.构造器注入

    System.out.println("==========通过构造函数注入开始==============");
    IPay pay = new WebChatPay();//在外部创建依赖对象
    Restaurant restaurant = new Restaurant(pay);
    restaurant.transact(10);
    System.out.println("==========通过构造函数注入结束==============");
    

    image

    这时候我们就看到Restaurant将依赖的WeChatPay对象的创建和绑定转移到Restaurant类外部来实现了。这样就解除了Restaurant类与WeChatPay类的耦合关系。如果将支付方式改成Alipay,只需要定义一个Alipay类,然后在外部重新绑定依赖。不需要修改Restaurant类。
    

    0x02.属性注入

    System.out.println("==========通过属性注入开始==============");
    IPay paySetter = new WebChatPay();
    RestaurantBySetter restaurantSetter = new RestaurantBySetter();
    restaurantSetter.setPay(paySetter);
    restaurantSetter.transact(10);
    System.out.println("==========通过属性注入结束==============");
    

    image

    0x03.接口注入

    System.out.println("==========通过接口注入开始==============");
    IPay payInterface = new WebChatPay();
    RestaurantByInterface restaurantInterface = new RestaurantByInterface();
    restaurantInterface.extraInstance(payInterface);
    restaurantInterface.transact(10);
    System.out.println("==========通过接口注入结束==============");
    

    image

    0x05.IOC容器

    DI框架,用来自动创建、维护依赖对象,并管理其生命周期。
    

    常使用的IOC容器有:
    Net:Ninject、Spring.NET、Unity、Autofac等
    Java:Spring等

    0x06.总结

    IOC带来好处:

    • 降低了各个组件之间的耦合性,增强了内聚性。
    • 大中型项目,团队分工明确,职责明确,便于测试
    • 使得模块具有热插拔特性,增加了模块的复用性
  • 相关阅读:
    juc之ConcurrentHashMap在我工作中的实践
    设计模式在我工作中的实践
    SpringBoot突报java.lang.NoSuchFieldError分析
    JQuery.UI类库AutoComplete 调用WebService进行模糊查询
    DevExpress控件库----LookUpEdit控件 和 GridLookUpEdit控件使用
    DevExpress控件库----FlyoutPanel提示控件
    Android学习笔记---Log与Activity生命周期
    DevExpress控件库---MarqueeProgressBarControl控件和ProgressBarControl控件
    DevExpress控件库---TokenEdit控件使用
    DevExpress控件库----SearchLookUpEdit控件
  • 原文地址:https://www.cnblogs.com/strivelearn/p/6246376.html
Copyright © 2011-2022 走看看