控制反轉是物件導向設計中解耦合的核心模式。傳統程式碼由呼叫端直接建立與管理依賴物件,IoC 將這項控制權移交給外部容器,實現元件裝配與生命週期的集中管理。依賴注入是 IoC 最主流的實現形式,讓容器全權負責依賴查詢與注入,受管元件僅暴露 setter、建構子或介面,達到與容器 API 完全解耦、易於單元測試與跨容器遷移的目標。

IoC 體現好萊塢原則。模板方法模式中,基類定義演算法骨架,具體步驟延遲至子類實現;IoC 容器定義流程框架,業務邏輯由外部物件注入參與。兩種參與方式:依賴查找(如 JNDI 主動查找)與依賴注入(容器推送)。

public class MyBusinessObject {
private DataSource ds;
private MyCollaborator myCollaborator;
public MyBusinessObject() {
Context ctx = null;
try {
ctx = new InitialContext();
ds = (DataSource) ctx.lookup("java:comp/env/dataSourceName");
myCollaborator = (MyCollaborator) ctx.lookup("java:comp/env/myCollaboratorName");
} ...
}
}
缺點顯而易見:程式碼強依賴 JNDI 環境,無法在應用伺服器外運行;更換查找方式需重構策略方法。
以 Content 為被注入的業務物件,MyBusiness 為接收端。
public class MyBusiness {
private Content myContent;
public MyBusiness(Content content) { this.myContent = content; }
public void doBusiness() { myContent.businessContent(); }
}
依賴在建構時強制注入,適合不可變依賴與必要依賴。
public class MyBusiness {
private Content myContent;
public void setContent(Content content) { this.myContent = content; }
public void doBusiness() { myContent.businessContent(); }
}
依賴可變更、可選擇性注入,靈活度最高,最常用。
public interface InContent { void createContent(Content content); }
public class MyBusiness implements InContent {
private Content myContent;
public void createContent(Content content) { this.myContent = content; }
public void doBusiness() { myContent.businessContent(); }
}
透過介面規範注入契約,容器調用介面方法完成注入,耦合度介於前兩者之間。
public static void main(String[] args) {
BeanFactory factory = getBeanFactory();
MessageRender mr = (MessageRender) factory.getBean("renderer");
mr.render();
}
從集中式 BeanFactory 獲取 Bean,本質區別於依賴查找:查找發生在啟動入口等特定集中位置,而非分散在業務元件內部。通常搭配 XML 配置實現物件集中管理。
掌握 IoC/DI 精髓,關鍵在於理解控制權轉移帶來的解耦價值,並根據依賴的必要性、可變性選擇建構子、設值或介面注入。Spring 等成熟容器已將這些模式封裝為聲明式配置,開發者專注於業務邏輯即可。