學習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進來的類