博客 / 詳情

返回

理解IOC

學習Spring,IOC是個繞不過去的話題。作為Spring的基礎,IOC有太多博客和教程了。這裏做個簡單的梳理,以找工作為例,談談我對IOC的理解。

在經典的MVC架構這,一般會有Dao、Service和Controller層,我們用Dao和Service舉例,項目結構如圖:
項目結構

其中WorkerService調用WorkDao的實現,代碼如下:

public class WorkerService {

    private WorkerDao workerDao = new WorkerDaoImpl();

    /**
     * 找工作
     */
    public void findJob(){
        workerDao.findJob();
    }
}

WorkerDaoImpl代碼如下:

public class WorkerDaoImpl implements WorkerDao {

    /**
     * 找工作
     */
    @Override
    public void findJob() {
        System.out.println("find job default");
    }
}

測試代碼:

public class WorkerServiceTest {

    @Test
    public void findJob() {
        WorkerService workerService = new WorkerService();
        workerService.findJob();
    }
}

到目前為止沒有問題,運行起來看下:
運行結果

類圖如下:

類圖

現在問題來了。我想要一個固定類型的工作,比如Java開發的工作。先添加一個對應的實現:

public class JavaWorkerDaoImpl implements WorkerDao {

    /**
     * 找工作
     */
    @Override
    public void findJob() {
        System.out.println("find java worker!");
    }
}

同樣,對應的WorkerService也修改一下:

public class WorkerService {

//    private WorkerDao workerDao = new WorkerDaoImpl();
    private WorkerDao workerDao = new JavaWorkerDaoImpl();
    /**
     * 找工作
     */
    public void findJob(){
        workerDao.findJob();
    }
}

可以看出,此時只需要把WorkerDao的實現改成JavaWorkerDaoImpl類就行了。運行:

同樣,如果需要其他的工作,只需要不同的實現就行了。唯一的問題是,需要改動業務代碼,來兼容客户端的需求。

接下來開始做一點修改。先把WorkerService做一點改造:

public class WorkerService {

//    private WorkerDao workerDao = new WorkerDaoImpl();
    private WorkerDao workerDao;
    /**
     * 找工作
     */
    public void findJob(){
        workerDao.findJob();
    }

    public WorkerDao getWorkerDao() {
        return workerDao;
    }

    public void setWorkerDao(WorkerDao workerDao) {
        this.workerDao = workerDao;
    }
}

這樣客户端的測試代碼就成了這樣:

public class WorkerServiceTest {

    @Test
    public void findJob() {
        WorkerService workerService = new WorkerService();
        WorkerDao workerDao = new WorkerDaoImpl();
        workerService.setWorkerDao(workerDao);
        workerService.findJob();
    }
}

這個時候,workderDao實例化時,只需要客户端指定就行了,客户端可以按照自己想要的來set對應的WorkerDao的實現。這樣一來,對於客户端的需求變化,業務層不需要做任何修改。
看下此時的類圖:

這裏有四個角色:WorkerDao及其實現類、WorkerService業務類、Test類(客户端)。以目前這種方式解耦了業務層和客户端,業務類的代碼不會根據客户端的需求來改變。對比上面的圖可以看出,業務類WorkerService並不直接管理WorkerDao,業務更內聚。

現在回到IOC。所謂控制反轉,就是要把對象的管理權交出去。最開始的實現UserService類需要自己來new WorkerDaoImpl()來實現WorkerDao,這樣管理WorkerDao就成了WorkerService來做的了。後續的實現則是把WorkerDao的實現交給客户端來完成,把控制權交給了客户端。

  • 控制:誰來創建對象,誰就有控制權
  • 反轉:對象的創建不再由業務控制,業務類只需要被動地接收客户端set進來的類
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.