但这样会带来一个问题,就是给调用端带来了麻烦,相当于把对Bus的依赖,从Worker类转移到了它的调用端,那它的调用端也会强依赖Bus,这本不属于调用端的职责,所以没有从根本上解决问题 。而且每次调用都要传一个Vehicle对象进来,很不合理,管理对象也比较麻烦 。
那你可能会想,我搞个第三方容器不就行了吗,这样每次去第三方容器里面拿:
public class Worker() {private String name;private String home;private String office;// 第三方容器private VehicleContainer container;// 通过容器取public void goToWork() {container.getTodayVehicle().take(name, home, office);}} 复制代码
文章插图
这样当然也能解决,但不是最优雅的解决方案,因为你每个Bean都需要依赖Container 。那我们能不能Worker类不依赖任何东西,包括Container,实现上班这个功能呢?当然可以,且听下文分析 。
依赖注入更优雅的方案就是使用依赖注入(Dependency Injection) 。我不想使用Container,每次还要主动去拿 。我想在自己被创建的时候(或者创建后),我所依赖的对象就自动被设置好了 。
文章插图
同时,这还是一种“无侵入”的方式,我们的业务代码里面可以不用写任何关于IoC的代码 。这样即使我们某一天换了IoC框架,我们的代码也不需要做任何修改 。
实现依赖注入大概有三种方式:构造器注入,方法注入和属性注入 。
构造器注入顾名思义,就是通过构造器的方式,把依赖的对象注入进来 。这样在new一个对象的时候,就完成了它依赖的对象的装配 。
public class Worker() {private String name;private String home;private String office;private Vehicle vehicle;// 通过构造器把要依赖的对象传进来public Worker(Vehicle vehicle) {this.vehicle = vehicle;}// 直接用public void goToWork() {vehicle.take(name, home, office);}}复制代码
setter方法注入另一种方式是使用方法注入,一般是使用要依赖的对象对应的属性的setter方法来注入 。比如:public class Worker() {private String name;private String home;private String office;private Vehicle vehicle;// 通过setter方法注入public void setVehicle(Vehicle vehicle) {this.vehicle = vehicle;}// 直接用public void goToWork() {vehicle.take(name, home, office);}}复制代码
属性注入构造器和setter方法都有些麻烦,需要写额外的代码 。要是容器可以通过反射直接注入进来就好了,这样代码看起来比较干净 。比如:public class Worker() {private String name;private String home;private String office;// 容器直接通过反射把相应的对象注入进来private Vehicle vehicle;// 直接用public void goToWork() {vehicle.take(name, home, office);}}复制代码
控制反转容器前面反复提到的一个词,叫“第三方容器”,其实就是IoC容器 。所谓IoC容器,就是可以生产和管理要依赖的对象,然后通过合适的时机注入进来 。IoC容器并不等于Spring 。还有其它IoC容器框架,比如google开发的Guice等,甚至我们可以自己开发一个轻量级的IoC容器 。其实IoC容器实现起来并不难 。
只是我们平常用Spring比较多,它又提供了非常好用的IoC功能,所以大多数项目,我们都是用Spring的IoC了 。Spring作为IoC容器还是非常成熟和稳定的 。
依赖注入和控制反转是什么关系?2004年,Martin Fowler探讨了同一个问题,既然IOC是控制反转,那么到底是“哪些方面的控制被反转了呢?”,经过详细地分析和论证后,他得出了答案:“获得依赖对象的过程被反转了” 。控制被反转之后,获得依赖对象的过程由自身管理变为了由IOC容器主动注入 。于是,他给“控制反转”取了一个更合适的名字叫做“依赖注入(Dependency Injection)” 。他的这个答案,实际上给出了实现IOC的方法:注入 。所谓依赖注入,就是由IOC容器在运行期间,动态地将某种依赖关系注入到对象之中 。
所以,依赖注入(DI)和控制反转(IOC)是从不同的角度的描述的同一件事情,就是指通过引入IOC容器,利用依赖关系注入的方式,实现对象之间的解耦 。控制反转是解决问题的一种思路和方法论,依赖注入是它的具体实现方式 。
在Spring中使用IoC首先要明确Bean的概念,Spring把需要纳入IoC容器观察的对象称为Bean 。
一些对象是不用交给Spring管理的,比如POJO对象,类似DO、DTO等对象(包括DDD中的领域模型),它们都是可以在程序里面通过new或者builder来创建的,因为创建的时候要给它们的一些属性赋值,而且在使用这些类时,没法使用“依赖倒置原则” 。
推荐阅读
- 饮食|关于维生素是否能帮助你减肥,这些真相你知道吗?
- spring框架之AOP面向切面编程
- 关于下一代智能手机的谈论 人工智能和云赋予手机完全个性化
- 看电视的利与弊
- 中国关于美人鱼的传说
- 韩信关于他与刘邦之间不同点的描述
- 交换机配置指南半分钟即可掌握关于SSL配置的内容
- 曹丕把曹彰杀了吗
- 关于人性的恶经典名句有哪些?
- 一文让你读懂JAVA.IO、字符编码、URL和Spring.Resource