激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - Java教程 - Java使用IOC控制反轉(zhuǎn)的三種設(shè)計(jì)模式詳解

Java使用IOC控制反轉(zhuǎn)的三種設(shè)計(jì)模式詳解

2021-01-20 14:42yoodb Java教程

這篇文章主要為大家詳細(xì)介紹了Java使用IOC控制反轉(zhuǎn)的三種設(shè)計(jì)模式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

對于許多開發(fā)人員來說,控制反演(IoC)都是一個(gè)模糊的概念,因?yàn)樗麄冊诂F(xiàn)實(shí)世界中很少或沒有被應(yīng)用過。在最好的情況下,控制反演(IoC)可以加單的認(rèn)為是等效于依賴注入(DI)。實(shí)際上,只有在翻轉(zhuǎn)控制與依賴注入雙方都只是反映翻轉(zhuǎn)依賴管理控制的時(shí)候,才認(rèn)為兩者是等效的。雖然,依賴注入實(shí)際上是IoC的一種眾所周知的形式。但是,事實(shí)上IoC卻是一個(gè)相對更為廣泛的軟件設(shè)計(jì)范例,可以通過多種模式來進(jìn)行實(shí)現(xiàn)。在本文中,我們將介紹依賴注入,觀察者模式和模板方法模式如何實(shí)現(xiàn)控制反轉(zhuǎn)的。

正如許多其他設(shè)計(jì)模式,是從各種各樣的使用場景中總結(jié)出來的,IoC的實(shí)現(xiàn)方式,也是類似的一種適合開發(fā)者使用的折中方式:

一方面,高度解耦組件的設(shè)計(jì),以及將應(yīng)用邏輯封裝在一個(gè)單一的地方,是實(shí)現(xiàn)IoC的直接而又自然的一種方式。
另一方面,上述實(shí)現(xiàn)需要至少需要構(gòu)建一個(gè)間接層,然而在某些用例中,這可能又是一種過度設(shè)計(jì)了。
接下來,不妨看幾個(gè)具體的實(shí)現(xiàn),這將有助于您了解,如何在這些屬性之間進(jìn)行權(quán)衡折中。

IOC范式揭秘

控制反轉(zhuǎn)是一種帶有某些特征的模式。下面,給出了由Martin Fowler給出的一個(gè)IOC經(jīng)典范例,該范例實(shí)現(xiàn)的功能是從控制臺中收集用戶數(shù)據(jù)。

?
1
2
3
4
5
6
7
8
9
10
11
12
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();
    }
  }
}

這個(gè)用例中,在main方法中進(jìn)行流程控制:在無限循環(huán)調(diào)用中,讀取用戶輸入,并將讀取的內(nèi)容輸出到控制臺上。完全又main方法控制何時(shí)去讀取用戶輸入,何時(shí)去輸出。

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

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

這種情況下,控制已經(jīng)被有效的反轉(zhuǎn)了。

從更通用的角度來看,由框架定義的每個(gè)可調(diào)用擴(kuò)展點(diǎn)(以接口實(shí)現(xiàn),實(shí)現(xiàn)繼承(也稱為子類)的形式)是IoC的一種明確定義的形式。

看下,下述這個(gè)簡單的Servlet例子:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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這個(gè)子類。在由servlet容器創(chuàng)建之后,當(dāng)收到servlet的GET和POST的HTTP請求,doGet()和doPost()方法中的代碼會分別自動(dòng)調(diào)用。

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

事實(shí)上,servlet的方法是模板方法模式的實(shí)現(xiàn),稍后我們再深入討論。

使用那些通過提供可擴(kuò)展API,秉承開閉原則的框架時(shí),使用框架的開發(fā)人員的角色,最終被歸結(jié)為定義自己的一組自定義類,即開發(fā)人員要么通過實(shí)現(xiàn)框架提供的一個(gè)或多個(gè)接口方式,要么通過繼承現(xiàn)有基類的方式。反過來,類的實(shí)例卻是直接框架進(jìn)行實(shí)例化,并且這些事例是被框架調(diào)用的。

此處引用Fowler的話:該框架調(diào)用開發(fā)人員,而不是開發(fā)人員調(diào)用該框架。因此,IoC通常被稱為好萊塢原則:不要打電話給我們,我們會打電話給你。

IOC的實(shí)現(xiàn)方式

該問題上,顯而易見的是,實(shí)現(xiàn)控制反轉(zhuǎn)是有幾種不同方法的。我們不妨來總結(jié)一下,那些常見的實(shí)現(xiàn)方式。

注入依賴實(shí)現(xiàn)IOC
如前所述,注入依賴是IOC的一種實(shí)現(xiàn)方式,而且是最常見的一種面向?qū)ο笤O(shè)計(jì)方式。但是,思考一下:注入依賴究竟是如何達(dá)到控制反轉(zhuǎn)效果的呢?

為了回答這個(gè)問題,我們給出如下一個(gè)原始的例子:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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,用于在一個(gè)隊(duì)列中去存放User對象(為了簡單明了,此處忽略User的具體實(shí)現(xiàn))。AbstractUserQueue則是為后續(xù)的繼承類,提供了一些公用的方法實(shí)現(xiàn)。最后的UserFifoQueue 和 UserLifoQueue,則是分別實(shí)現(xiàn)了FIFO 和 LIFO 隊(duì)列。

這是,實(shí)現(xiàn)子類多態(tài)性的一種有效方式。但是這具體用什么來買我們好處呢?實(shí)際上,好處還是蠻多的。

通過創(chuàng)建一個(gè)依賴于UserQueue抽象類型(也稱為DI術(shù)語中的服務(wù))的客戶端類,可以在運(yùn)行時(shí)注入不同的實(shí)現(xiàn),無需會重構(gòu)使用客戶端類的代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
public class UserProcessor {
  private UserQueue userQueue;
 
  public UserProcessor(UserQueue userQueue) {
    this.userQueue = userQueue;
  }
 
  public void process() {
    // process queued users here
  }
 
}

UserProcessor展示了,注入依賴確實(shí)是IOC的一種方式。

我們可以通過一些硬編碼方式 如 new 操作,直接在構(gòu)造函數(shù)中實(shí)例化在UserProcessor中獲取對隊(duì)列的依賴關(guān)系。但是,這是典型的代碼硬編程,它引入了客戶端類與其依賴關(guān)系之間的強(qiáng)耦合,并大大降低了可測性。耳邊警鐘聲聲想起啦!不是嗎?是的,這樣設(shè)計(jì)真的很挫。

該類在構(gòu)造函數(shù)中聲明對抽象類 UserQueue 的依賴。也就是說,依賴關(guān)系不再通過 在構(gòu)造函數(shù)中使用 new 操作, 相反,通過外部注入的方式,要么使用依賴注入框架(如CDI和谷歌的Guice),要么使用factory或builders模式。

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

?
1
2
3
4
5
6
7
8
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();
}

上述方式達(dá)到了預(yù)期效果,而且對UserLifoQueue的注入也簡單明了。顯而易見,DI確實(shí)是實(shí)現(xiàn)IOC的一種方式(該例中,DI是實(shí)現(xiàn)IOC的一個(gè)中間層)。

觀察者模式實(shí)現(xiàn)IOC

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

在一個(gè)典型的實(shí)現(xiàn)中,一到多個(gè)觀察者綁定到可觀察對象(也稱為模式術(shù)語中的主題),例如通過調(diào)用addObserver方法進(jìn)行綁定。一旦定義了被觀察者和觀察者之間的綁定,則被觀察者狀態(tài)的變遷都會觸發(fā)調(diào)用觀察者的操作。

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

?
1
2
3
4
5
6
@FunctionalInterface
public interface SubjectObserver {
 
  void update();
 
}

值發(fā)生改變時(shí),會觸發(fā)調(diào)用上述這個(gè)很簡單的觀察者。真實(shí)情況下,通常會提供功能更豐富的API,如需要保存變化的實(shí)例,或者新舊值,但是這些都不需要觀察action(行為)模式,所以這里舉例盡量簡單。

下面,給出一個(gè)被觀察者類:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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類中,當(dāng)通過setter方法變更其狀態(tài)事,都會觸發(fā)調(diào)用綁定到它的觀察者。

使用主題觀察者和主題,以下是實(shí)例給出了觀察方式:

?
1
2
3
4
5
6
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");
}

每當(dāng)User對象的狀態(tài)通過setter方法進(jìn)行修改時(shí),觀察者將被通知并向控制臺打印出一條消息。到目前為止,給出了觀察者模式的一個(gè)簡單用例。不過,通過這個(gè)看似簡單的用例,我們了解到在這種情況下控制是如何實(shí)現(xiàn)反轉(zhuǎn)的。

觀察者模式下,主題就是起到”框架層“的作用,它完全主導(dǎo)何時(shí)何地去觸發(fā)誰的調(diào)用。觀察者的主動(dòng)權(quán)被外放,因?yàn)橛^察者無法主導(dǎo)自己何時(shí)被調(diào)用(只要它們已經(jīng)被注冊到某個(gè)主題中的話)。這意味著,實(shí)際上我們可以發(fā)現(xiàn)控制被反轉(zhuǎn)的”事發(fā)地“ – - – 當(dāng)觀察者綁定到主題時(shí):

?
1
2
user.addObserver(() -> System.out.println(
      "Observable subject " + user + " has changed its state."));

上述用例,簡要說明了為什么,觀察者模式(或GUI驅(qū)動(dòng)環(huán)境中的action監(jiān)聽器)是實(shí)現(xiàn)IoC的一種非常簡單的方式。正是以這種分散式設(shè)計(jì)軟件組件的形式,使得控制得以發(fā)生反轉(zhuǎn)。

通過模板方法模式實(shí)現(xiàn)IoC

模板方法模式實(shí)現(xiàn)的思想是在一個(gè)基類中通過幾個(gè)抽象方法(也稱算法步驟)來定義一個(gè)通用的算法,然后讓子類提供具體的實(shí)現(xiàn),這樣保證算法結(jié)構(gòu)不變。

我們可以應(yīng)用這個(gè)思想,定義一個(gè)通用的算法來處理領(lǐng)域?qū)嶓w:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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() 方法是個(gè)模板方法,它定義了處理實(shí)體的算法,而抽象方法代表了算法的步驟,它們必須在子類中實(shí)現(xiàn)。通過多次繼承 EntityProcessor 并實(shí)現(xiàn)不同的抽象方法,可以實(shí)現(xiàn)若干算法版本。

雖然這說清楚了模板方法模式背后的動(dòng)機(jī),但人們可能想知道為什么這是 IoC 的模式。

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

總結(jié)

盡管控制反轉(zhuǎn)普遍存在于 Java 的生態(tài)系統(tǒng)中,特別是很多框架普遍采用了依賴注入,但對于多數(shù)開發(fā)者來說,這個(gè)模式仍然很模糊,對其應(yīng)用也受限于依賴注入。在這篇文章中,我展示了幾種實(shí)際可用的實(shí)現(xiàn) IoC 的方法,闡明了這一概念。

依賴注入:從客戶端獲得依賴關(guān)系的控制不再存在于這些類中。它存由底層的注入器 / DI 框架來處理。
觀察者模式:當(dāng)主體發(fā)生變化時(shí),控制從觀察者傳遞到主體。
模板方法模式:控制發(fā)生在定義模板方法的基類中,而不是實(shí)現(xiàn)算法步驟的子類中。
像往常一樣,怎樣以及何時(shí)使用 IoC 是通過對每個(gè)用例的分析來決定的,不要為了 IoC 而 IoC。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。

原文鏈接:https://blog.yoodb.com/yoodb/article/detail/1353

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25
主站蜘蛛池模板: 日韩一级成人 | 中文字幕22页 | 91精品国产99久久久久久 | 亚洲三区精品 | 黄色特级毛片 | 欧美精品久久久久久久久老牛影院 | 久久精品欧美视频 | 国产视频导航 | 青热久思思 | 久久久线视频 | 亚洲性生活免费视频 | 一本色道久久综合亚洲精品小说 | 精品国产亚洲人成在线 | 免费看欧美黑人毛片 | 黄污在线看 | 中国免费一级毛片 | 欧美成人精品一区 | 亚洲影院在线 | 片在线观看 | 特大黑人videos与另类娇小 | 国产一级不卡毛片 | 国产99久久精品一区二区 | 国产亚洲精彩视频 | 99精品国产在热久久婷婷 | 久久久综合久久久 | 超久久 | 久久精品国产亚洲一区二区 | 人人玩人人爽 | 日本xxxx色视频在线观看免费, | 久久精品99久久久久久2456 | 91精品国产91久久久久久蜜臀 | 黄色久 | 2021狠狠操 | 伊人av影院 | 欧美日本色 | 视频一区二区不卡 | 日韩精品久久久久久久九岛 | 成人毛片视频免费 | 国产午夜探花 | 国产精品自拍av | 毛片大全在线观看 |