控制反轉(Inversion of Control,英文縮寫為IoC)是架構的重要特徵,並非物件導向程式設計的專用術語。它與依賴注入(Dependency Injection,簡稱DI)和依賴查找(Dependency Lookup)並沒有關係。
使用過Spring的開發者應該都對IOC控制反轉功能有所了解,最開始學習時應該都知道使用依賴注入來實現IOC的功能,本文來介紹使用IOC控制反轉思想的幾種設計模式。
依賴注入來實作IOC
注入依賴是IOC最基本的實作方式,也是最常用的一種物件導向設計方式之一。注入依賴如何達到控制反轉效果,先以一個例子開始:
public interface UserQueue {void add(User user);void remove(User user); User get(); }public abstract class AbstractUserQueue implements UserQueue {protected LinkedList<user> queue = new LinkedList(); @Overridepublic void add(User user) { queue.addFirst(user); } @Overridepublic void remove(User user) { queue.remove(user); } @Overridepublic abstract User get(); }public class UserFifoQueue extends AbstractUserQueue {public User get() {return queue.getLast(); } }public class UserLifoQueue extends AbstractUserQueue {public User get() {return queue.getFirst(); } }</user>
#UserQueue
介面定義了公共的方法,用於在一個佇列中去存放User物件。 AbstractUserQueue則是為後續的繼承類,提供了一些公用的方法實作。最後的UserFifoQueue
和 UserLifoQueue,則分別實作了FIFO 和 LIFO 佇列。
這是實作子類別多態性的一種有效方式。
透過建立一個依賴UserQueue抽象類型(也稱為DI術語中的服務)的客戶端類,可以在執行時間注入不同的實現,而無需重構使用客戶端類別的程式碼:
public class UserProcessor {private UserQueue userQueue;public UserProcessor(UserQueue userQueue) {this.userQueue = userQueue; }public void process() {// process queued users here } }
UserProcessor展示了依賴注入確實是IOC的一種方式。
我們可以透過一些硬編碼方式 如 new 操作,直接在建構函數中實例化在UserProcessor中取得對佇列的依賴關係。但這是典型的程式碼硬編程,它引入了客戶端類別與其依賴關係之間的強耦合,並大大降低了可測性。
該類別在建構函式中宣告對抽象類別 UserQueue
的相依性。也就是說,依賴關係不再透過在建構函式中使用 new 操作, 相反,透過外部注入的方式,要麼使用依賴注入框架,要麼使用factory或builders模式。
使用依賴注入,客戶端類別的依賴關係的控制,不再位於這些類別中;而是在註入器中進行,看如下程式碼:
public static void main(String[] args) { UserFifoQueue fifoQueue = new UserFifoQueue(); fifoQueue.add(new User("user1")); fifoQueue.add(new User("user2")); fifoQueue.add(new User("user3")); UserProcessor userProcessor = new UserProcessor(fifoQueue); userProcessor.process(); }
#上述方式達到了預期效果,而且對UserLifoQueue的注入也簡單明了。
觀察者模式實現IOC
直接透過觀察者模式實現IOC,也是一種常見的直覺方式。廣義上講,透過觀察者實現IOC,觀察者模式通常用於在模型視圖的上下文中,追蹤模型物件的狀態的變化。
在一個典型的實作中,一到多個觀察者綁定到可觀察對象(也稱為模式術語中的主題),例如透過呼叫addObserver方法進行綁定。一旦定義了被觀察者和觀察者之間的綁定,則被觀察者狀態的變化都會觸發呼叫觀察者的操作。看下面範例:
public interface SubjectObserver {void update(); }
值改變時,會觸發呼叫上述這個很簡單的觀察者。在真實情況下,通常會提供功能更豐富的API,如需要保存變化的實例,或者新舊值,但是這些都不需要觀察action(行為)模式,所以這裡舉例盡量簡單。
下面,給一個被觀察者類別:
public class User {private String name;private List<subjectobserver> observers = new ArrayList();public User(String name) {this.name = name; }public void setName(String name) {this.name = name; notifyObservers(); }public String getName() {return name; }public void addObserver(SubjectObserver observer) { observers.add(observer); }public void deleteObserver(SubjectObserver observer) { observers.remove(observer); }private void notifyObservers(){ observers.stream().forEach(observer -> observer.update()); } }</subjectobserver>
User類別中,當透過setter方法變更其狀態事,都會觸發呼叫綁定到它的觀察者。
使用主題觀察者和主題,以下是實例給出了觀察方式:
public static void main(String[] args) { User user = new User("John"); user.addObserver(() -> System.out.println("Observable subject " + user + " has changed its state.")); user.setName("Jack"); }
每當User物件的狀態透過setter方法進行修改時,觀察者將被通知並向控制台列印出一條訊息。到目前為止,給出了觀察者模式的一個簡單用例。不過,透過這個看似簡單的用例,我們了解到在這種情況下控制是如何實現反轉的。
觀察者模式下,主題就是起到」框架層「的作用,它完全主導何時何地去觸發誰的調用。觀察者的主動權被外放,因為觀察者無法主導自己何時被調用(只要它們已經被註冊到某個主題中的話)。這意味著,實際上我們可以發現控制被反轉的」事發地「— 當觀察者綁定到主題時:
user.addObserver(() -> System.out.println("Observable subject " + user + " has changed its state."));
上述用例,简要说明了为什么观察者模式是实现IoC的一种非常简单的方式。正是以这种分散式设计软件组件的形式,使得控制得以发生反转。
模板方法模式实现IOC
模板方法模式实现的思想是在一个基类中通过几个抽象方法来定义一个通用的算法,然后让子类提供具体的实现,这样保证算法结构不变。
我们可以应用这个思想,定义一个通用的算法来处理领域实体,看例子:
public abstract class EntityProcessor {public final void processEntity() { getEntityData(); createEntity(); validateEntity(); persistEntity(); }protected abstract void getEntityData();protected abstract void createEntity();protected abstract void validateEntity();protected abstract void persistEntity(); }
processEntity()
方法是个模板方法,它定义了处理实体的算法,而抽象方法代表了算法的步骤,它们必须在子类中实现。通过多次继承 EntityProcessor 并实现不同的抽象方法,可以实现若干算法版本。
虽然这说清楚了模板方法模式背后的动机,但人们可能想知道为什么这是 IOC 的模式。
典型的继承中,子类调用基类中定义的方法。而这种模式下,相对真实的情况是:子类实现的方法(算法步骤)被基类的模板方法调用。因此,控制实际是在基类中进行的,而不是在子类中。
总结:
依赖注入:从客户端获得依赖关系的控制不再存在于这些类中。它存由底层的注入器 / DI 框架来处理。
观察者模式:当主体发生变化时,控制从观察者传递到主体。
模板方法模式:控制发生在定义模板方法的基类中,而不是实现算法步骤的子类中。
以上是IOC控制反轉實例詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本文討論了使用Maven和Gradle進行Java項目管理,構建自動化和依賴性解決方案,以比較其方法和優化策略。

本文使用Maven和Gradle之類的工具討論了具有適當的版本控制和依賴關係管理的自定義Java庫(JAR文件)的創建和使用。

本文討論了使用咖啡因和Guava緩存在Java中實施多層緩存以提高應用程序性能。它涵蓋設置,集成和績效優勢,以及配置和驅逐政策管理最佳PRA

本文討論了使用JPA進行對象相關映射,並具有高級功能,例如緩存和懶惰加載。它涵蓋了設置,實體映射和優化性能的最佳實踐,同時突出潛在的陷阱。[159個字符]

Java的類上載涉及使用帶有引導,擴展程序和應用程序類負載器的分層系統加載,鏈接和初始化類。父代授權模型確保首先加載核心類別,從而影響自定義類LOA


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver Mac版
視覺化網頁開發工具

WebStorm Mac版
好用的JavaScript開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),