中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何在Java中利用IOC控制反轉

發布時間:2021-02-22 15:38:48 來源:億速云 閱讀:111 作者:Leah 欄目:編程語言

這篇文章給大家介紹如何在Java中利用IOC控制反轉,內容非常詳細,感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助。

Java的特點有哪些

Java的特點有哪些 1.Java語言作為靜態面向對象編程語言的代表,實現了面向對象理論,允許程序員以優雅的思維方式進行復雜的編程。 2.Java具有簡單性、面向對象、分布式、安全性、平臺獨立與可移植性、動態性等特點。 3.使用Java可以編寫桌面應用程序、Web應用程序、分布式系統和嵌入式系統應用程序等。

IOC范式揭秘

控制反轉是一種帶有某些特征的模式。下面,給出了由Martin Fowler給出的一個IOC經典范例,該范例實現的功能是從控制臺中收集用戶數據。

public static void main(String[] args) {
  while (true) {
    BufferedReader userInputReader = new BufferedReader(
        new InputStreamReader(System.in));
    System.out.println("Please enter some text: ");
    try {
      System.out.println(userInputReader.readLine());
    } catch (IOException e) {
      e.printStackTrace();
    }
  }
}

這個用例中,在main方法中進行流程控制:在無限循環調用中,讀取用戶輸入,并將讀取的內容輸出到控制臺上。完全又main方法控制何時去讀取用戶輸入,何時去輸出。

考慮下,上述程序的一個新版本,該版本中需要通過圖形界面中的文本框來收件用戶輸入,另外還有個按鈕,該按鈕上綁定有一個action監聽器。這樣的話,用戶每次點擊按鈕,輸入的文本由監聽器收集并打印到面板。

在這個版本的程序中,它實際上是由事件監聽器模型(在這種情況下,這是框架)的控制下,調用開發者編寫的用于讀取和打印用戶輸入的代碼。簡單地說,框架將調用開發人員的代碼,而不是其他方式。該框架實際上是一個可擴展的結構,它為開發人員提供了一組注入自定義代碼段的切入點。

這種情況下,控制已經被有效的反轉了。

從更通用的角度來看,由框架定義的每個可調用擴展點(以接口實現,實現繼承(也稱為子類)的形式)是IoC的一種明確定義的形式。

看下,下述這個簡單的Servlet例子:

public class MyServlet extends HttpServlet {
 
  protected void doPost(
      HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    // developer implementation here
  }
 
  protected void doGet(
      HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    // developer implementation here
  }
 
}

此處,HttpServlet類(屬于框架)是完全控制程序的元素,而不是MyServlet這個子類。在由servlet容器創建之后,當收到servlet的GET和POST的HTTP請求,doGet()和doPost()方法中的代碼會分別自動調用。

與典型的繼承方式相比,即子類是控制的元素,而不是基類,該例中,控件已經被反轉了。

事實上,servlet的方法是模板方法模式的實現,稍后我們再深入討論。

使用那些通過提供可擴展API,秉承開閉原則的框架時,使用框架的開發人員的角色,最終被歸結為定義自己的一組自定義類,即開發人員要么通過實現框架提供的一個或多個接口方式,要么通過繼承現有基類的方式。反過來,類的實例卻是直接框架進行實例化,并且這些事例是被框架調用的。

此處引用Fowler的話:該框架調用開發人員,而不是開發人員調用該框架。因此,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<>();
 
  @Override
  public void add(User user) {
    queue.addFirst(user);
  }
 
  @Override
  public void remove(User user) {
    queue.remove(user);
  }
 
  @Override
  public 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();
  }
 
}

UserQueue 接口定義了公共的API,用于在一個隊列中去存放User對象(為了簡單明了,此處忽略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 操作, 相反,通過外部注入的方式,要么使用依賴注入框架(如CDI和谷歌的Guice),要么使用factory或builders模式。

簡而言之,使用DI,客戶端類的依賴關系的控制,不再位于這些類中;而是在注入器中進行:

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的注入也簡單明了。顯而易見,DI確實是實現IOC的一種方式(該例中,DI是實現IOC的一個中間層)。

觀察者模式實現IOC

直接通過觀察者模式實現IOC,也是一種常見的直觀方式。廣義上講,通過觀察者實現IOC,與前文提到的通過GUI界面中的action監聽器方式類似。但是在使用action監聽器情況下,只有在特定的用戶事件發生時(點擊鼠標,鍵盤或窗口事件等),才會發生調用。觀察者模式通常用于在模型視圖的上下文中,跟蹤模型對象的狀態的變遷。

在一個典型的實現中,一到多個觀察者綁定到可觀察對象(也稱為模式術語中的主題),例如通過調用addObserver方法進行綁定。一旦定義了被觀察者和觀察者之間的綁定,則被觀察者狀態的變遷都會觸發調用觀察者的操作。

為了深入了解這個概念,給出如下例子:

@FunctionalInterface
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());
  }
}

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."));

上述用例,簡要說明了為什么,觀察者模式(或GUI驅動環境中的action監聽器)是實現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 的模式。

典型的繼承中,子類調用基類中定義的方法。而這種模式下,相對真實的情況是:子類實現的方法(算法步驟)被基類的模板方法調用。因此,控制實際是在基類中進行的,而不是在子類中。
這也是 IoC 的典型例子,通過分層結構實現。這種情況下,模板方法只是可調的擴展點的一個漂亮的名字,被開發者用來管理自己的一系列實現。

關于如何在Java中利用IOC控制反轉就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

阿尔山市| 延寿县| 汕头市| 志丹县| 阳西县| 仲巴县| 大兴区| 洞头县| 郸城县| 宁化县| 杨浦区| 什邡市| 临清市| 阿巴嘎旗| 色达县| 涟源市| 永济市| 天柱县| 江阴市| 宁远县| 武山县| 泉州市| 丹寨县| 唐河县| 东阿县| 平潭县| 横峰县| 三门县| 闻喜县| 岢岚县| 榕江县| 象州县| 高淳县| 忻州市| 乐都县| 崇信县| 中西区| 南溪县| 台安县| 黔南| 陆良县|