『化主动为被动』 — 谈IoC与DI/DL

我们在前文中谈过了DI — Dependency Injection,并且说明了他对解耦合的便利性与重要性。还记得杀手的例子吗?不记得没关系,我们来复习一下:

// CoolKiller.java
public class CoolKiller implements Killer{
    Weapon weapon;

    public CoolKiller(Weapon weapon){
        this.weapon = weapon;
    }
    
    public void kill() {
        weapon.act();
    }
}

透过依赖注入,我们可以把武器的『何时使用』和『使用了会怎样』分别交给Killer和Weapon两个类别处理。这件事情其实也不是凭空想出来的 — 我可没那么聪明,你知道的。早在2004年,Martin Fowler就提出了想法,他的结论是:『因为依赖物件的获得被反转了,所以控制权也被反转了』。这个重要的观念,就是我们后来常听到的解耦合神器:『Inversion of Coltrol (IoC)』。

https://ithelp.ithome.com.tw/upload/images/20180101/20107429mtrkYwXT9W.jpg
我知道,我知道直接讲这些理论肯定让你想睡,什么什么巴黎铁塔翻过来又转过去的。不过听不懂又有什么关系,不懂理论又怎样,只要会用就好了不是吗?就像上面的杀手范例一样,那就是IoC的重要实行方法之一。

事情进到了企业级应用程序后有了变化。你可以想像,如果在你的系统哩,每个物件彼此之间都要这样先new出来再塞进另一个物件,然后再打包塞进第三层物件,虽然这样也可以达到降耦合的效果,但是你就是会打出很多次『长得很像的代码』。其实就是在你的主流程里面一直new一直new这样。

『这样有什么坏处?』其实没有。

在你的程序与公司规模都还在学生项目级别时,你当然还是可以在逻辑里混杂物件创建的处理,这当然没有差。当你的公司开始走向『企业级』规模时,可就不是这么一回事了。

企业级Web设计框架Spring可不允许工程师浪费时间再为了每个物件多打这两三行,他要我们连『这两三行都省起来』。亦即,他希望工程师只要管主流程的逻辑就好,创物件这种琐事,让框架替你完成。怎么做?Dependency Lookup噜!

简单来说,定义好每个物件包含哪些另外的物件 (在Sprint容器哩,我们管他叫Bean),定义好后,直接把Sprint容器启动(譬如直接启动Web Server),Spring会根据你提供的物件定义与彼此间的关系去创造Bean。光说不练可不行,我们来实际操作吧:

// CoolKiller.java
public class CoolKiller implements Killer{

    @Autowired
    Weapon weapon;
    
    //...Skip the rest

『什么,就这样?你啰哩八唆讲半天然后写起来就这样?』

对啊,就是要让你知道,虽然背后的原理啰哩八缩的,但Spring的目的就是要你的自刻代码越精简越好啊!啊不然你还要自己一行一行刻,还要Sprint做啥

所以简单来说,IoC是概念,他透过反转控制权的方式来达到降耦合的效果,而DI是一种实作方法,你必须主动创建物件并控制其生命周期,DL则是另一种,框架帮你管理了所有琐事。