剖析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带来好处:

  • 降低了各个组件之间的耦合性,增强了内聚性。
  • 大中型项目,团队分工明确,职责明确,便于测试
  • 使得模块具有热插拔特性,增加了模块的复用性
posted @ 2017-01-03 20:36  落叶飞逝的恋  阅读(289)  评论(0编辑  收藏  举报