<ul id="qxxfc"><fieldset id="qxxfc"><tr id="qxxfc"></tr></fieldset></ul>


      很長(zhǎng)一段時(shí)間里,我對(duì)控制反轉(zhuǎn)和依賴注入這兩個(gè)概念很模糊,閉上眼睛想一想,總有一種眩暈的感覺。但為了成為一名優(yōu)秀的 Java
      工程師,我花了一周的時(shí)間,徹底把它們搞清楚了。

      01、緊耦合


      在我們編碼的過程中,通常都需要兩個(gè)或者更多的類通過彼此的合作來實(shí)現(xiàn)業(yè)務(wù)邏輯,也就是說,某個(gè)對(duì)象需要獲取與其合作對(duì)象的引用,如果這個(gè)獲取的過程需要自己實(shí)現(xiàn),代碼的耦合度就會(huì)高,維護(hù)起來的成本就比較高。

      我們來通過實(shí)戰(zhàn)模擬一下。假如老王是少林寺的主持,他想讓小二和尚去掃達(dá)摩院的地,代碼可以這樣實(shí)現(xiàn)。

      小二類的代碼如下所示:
      public?class?Xiaoer?{
      ????public?void?saodi()?{
      ????????System.out.println("小二我在掃達(dá)摩院的地");
      ????}
      }

      老王類的代碼如下所示:
      public?class?Laowang?{
      ????public?void?mingling()?{
      ????????new?Xiaoer().saodi();
      ????}
      }

      測(cè)試類的代碼如下所示:
      public?class?Test?{

      ????public?static?void?main(String[]?args)?{
      ????????Laowang?laowang?=?new?Laowang();
      ????????laowang.mingling();
      ????}

      }

      Laowang 類的 mingling 方法中使用 new 關(guān)鍵字創(chuàng)建了一個(gè) Xiaoer
      類的對(duì)象——這種代碼的耦合度就很高,維護(hù)起來的成本就很高,為什么這么說呢?

      某一天,達(dá)摩院的地又臟了,老王主持想起了小二和尚,可小二和尚去練易筋經(jīng)了,讓誰去掃地呢,老王主持想起了小三和尚,于是 Laowang
      類就不得不重新下一個(gè)新的命令,于是代碼變成了這樣:
      public?class?Xiaosan?{
      ????public?void?saodi()?{
      ????????System.out.println("小三我在掃達(dá)摩院的地");
      ????}
      }
      public?class?Laowang?{
      ????public?void?mingling()?{
      ????????new?Xiaoer().saodi();
      ????}

      ????public?void?mingling1()?{
      ????????new?Xiaosan().saodi();
      ????}
      }

      假如小三和尚去挑水了,老王主持沒準(zhǔn)要下命令給小四和尚去掃達(dá)摩院的地。這樣下去的話,Laowang 這個(gè)類會(huì)瘋掉的。

      老王主持覺得自己堂堂一屆高僧,下個(gè)掃地的命令竟然這樣麻煩,他覺得很不爽。

      02、控制反轉(zhuǎn)

      我們得替老王主持想個(gè)辦法對(duì)不對(duì)?

      不如把這個(gè)掃地的差事交給老王的師弟老方吧,老方負(fù)責(zé)去叫小二和尚還是小三和尚還是小四和尚去執(zhí)行老王主持的命令。代碼可以這樣實(shí)現(xiàn)。

      定義一個(gè)掃地和尚的接口,代碼如下所示:
      public?interface?Heshang?{
      ????void?saodi();
      }

      小二類的代碼修改如下所示:
      public?class?Xiaoer?implements?Heshang?{

      ????@Override
      ????public?void?saodi()?{
      ????????System.out.println("小二我在掃達(dá)摩院的地");????????
      ????}

      ????public?boolean?isYijinjing()?{
      ????????//?星期三的時(shí)候小二和尚要練易筋經(jīng)
      ????????return?false;
      ????}
      }

      小三類的代碼修改如下所示:
      public?class?Xiaosan?implements?Heshang?{

      ????@Override
      ????public?void?saodi()?{
      ????????System.out.println("小三我在掃達(dá)摩院的地");????????
      ????}
      }

      老方類的代碼如下所示:
      public?class?Laofang?{
      ????public?static?Heshang?getSaodiseng()?{
      ????????Xiaoer?xiaoer?=?new?Xiaoer();
      ????????if?(xiaoer.isYijinjing())?{
      ????????????return?new?Xiaosan();
      ????????}
      ????????return?xiaoer;
      ????}
      }

      如果老方確認(rèn)小二和尚在練易筋經(jīng),就叫小三和尚。

      老王類的代碼修改如下所示:
      public?class?Laowang?{
      ????public?void?mingling()?{
      ????????Laofang.getSaodiseng().saodi();
      ????}
      }

      測(cè)試類的代碼不改變,如下所示:
      public?class?Test?{

      ????public?static?void?main(String[]?args)?{
      ????????Laowang?laowang?=?new?Laowang();
      ????????laowang.mingling();
      ????}

      }

      老王現(xiàn)在是不是省心多了,他只管下命令,該叫誰去掃達(dá)摩院的地由他師弟老方去負(fù)責(zé)。

      我們替老王想的這個(gè)辦法就叫控制反轉(zhuǎn)(Inversion of Control,縮寫為 IoC),它不是一種技術(shù),而是一種思想——指導(dǎo)我們?cè)O(shè)計(jì)出松耦合的程序。

      控制反轉(zhuǎn)從詞義上可以拆分為“控制”和“反轉(zhuǎn)”,說到控制,就必須找出主語和賓語,誰控制了誰;說到反轉(zhuǎn),就必須知道正轉(zhuǎn)是什么。

      你看,在緊耦合的情況下,老王下命令的時(shí)候自己要通過 new
      關(guān)鍵字創(chuàng)建依賴的對(duì)象(小二和尚或者小三和尚);而控制反轉(zhuǎn)后,老王要找的掃地和尚由他師弟老方負(fù)責(zé),也就是說控制權(quán)交給了老方,是不是反轉(zhuǎn)了呢?

      03、依賴注入

      依賴注入(Dependency Injection,簡(jiǎn)稱 DI)是實(shí)現(xiàn)控制反轉(zhuǎn)的主要方式:在類 A 的實(shí)例創(chuàng)建過程中就創(chuàng)建了依賴的 B
      對(duì)象,通過類型或名稱來判斷將不同的對(duì)象注入到不同的屬性中。大概有 3 種具體的實(shí)現(xiàn)形式:

      1)基于構(gòu)造函數(shù)。實(shí)現(xiàn)特定參數(shù)的構(gòu)造函數(shù),在新建對(duì)象時(shí)傳入所依賴類型的對(duì)象。

      老王類的代碼修改如下所示:
      public?class?Laowang?{
      ????private?Heshang?saodiseng;

      ????public?Laowang(Heshang?saodiseng)?{
      ????????this.saodiseng?=?saodiseng;
      ????}
      ????public?void?mingling()?{
      ???????this.saodiseng.saodi();
      ????}
      }

      測(cè)試類的代碼修改如下所示:
      public?class?Test?{

      ????public?static?void?main(String[]?args)?{
      ????????Laowang?laowang?=?new?Laowang(new?Xiaosan());
      ????????laowang.mingling();
      ????}

      }

      這時(shí)候,控制權(quán)掌握在測(cè)試類的手里,它決定派小二和尚還是小三和尚去執(zhí)行老王的掃地命令。

      2)基于 set 方法。實(shí)現(xiàn)特定屬性的 public set 方法,讓外部容器調(diào)用傳入所依賴類型的對(duì)象。

      老王類的代碼修改如下所示:
      public?class?Laowang?{
      ????private?Heshang?saodiseng;

      ????public?Heshang?getSaodiseng()?{
      ????????return?saodiseng;
      ????}

      ????public?void?setSaodiseng(Heshang?saodiseng)?{
      ????????this.saodiseng?=?saodiseng;
      ????}

      ????public?void?mingling()?{
      ???????this.getSaodiseng().saodi();
      ????}
      }

      測(cè)試類的代碼修改如下所示:
      public?class?Test?{

      ????public?static?void?main(String[]?args)?{
      ????????Laowang?laowang?=?new?Laowang();
      ????????Xiaosan?xiaosan?=?new?Xiaosan();
      ????????laowang.setSaodiseng(xiaosan);
      ????????laowang.mingling();
      ????}

      }

      這時(shí)候,控制權(quán)仍然掌握在測(cè)試類的手里,它決定派小二和尚還是小三和尚去執(zhí)行老王的掃地命令。

      3)基于接口。實(shí)現(xiàn)特定接口以供外部容器注入所依賴類型的對(duì)象,這種做法比較構(gòu)造函數(shù)和 set 方法更為復(fù)雜,這里就此略過。

      可能有人會(huì)把控制反轉(zhuǎn)等同于依賴注入,但實(shí)際上它們有著本質(zhì)上的不同:控制反轉(zhuǎn)是一種思想,而依賴注入是實(shí)現(xiàn)控制反轉(zhuǎn)的一種形式。

      04、Spring 框架

      當(dāng)我們搞清楚控制反轉(zhuǎn)和依賴注入的概念后,就可以順帶了解一下大名鼎鼎的 Spring 框架??刂品崔D(zhuǎn)是 Spring 框架的核心,貫穿始終。Spring
      中依賴注入有兩種實(shí)現(xiàn)方式:set 方式(傳值方式)和構(gòu)造器方式(引用方式)。

      首先,我們需要在 pom.xml 文件中加入 Spring 的依賴項(xiàng),代碼如下所示:
      <dependency>
      ????<groupId>org.springframework</groupId>
      ????<artifactId>spring-context-support</artifactId>
      ????<version>4.3.2.RELEASE</version>
      </dependency>

      其次,我們將 Laowang 類修改為如下內(nèi)容:
      public?class?Laowang?{
      ????private?Heshang?saodiseng;

      ????public?Laowang(Heshang?saodiseng)?{
      ????????this.saodiseng?=?saodiseng;
      ????}
      ????public?void?mingling()?{
      ???????this.saodiseng.saodi();
      ????}
      }

      然后,我們創(chuàng)建一個(gè) Spring 的配置文件 application.xml,內(nèi)容如下所示:
      <?xml?version="1.0"?encoding="UTF-8"?>
      <beans?xmlns="http://www.springframework.org/schema/beans"
      ??xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      ??xsi:schemaLocation=
      "http://www.springframework.org/schema/beans?http://www.springframework.org/schema/beans/spring-beans.xsd">

      ??<bean?id="laowang"?class="com.cmower.java_demo.ioc.Laowang">
      ????<constructor-arg?ref="saodiseng"?/>
      ??</bean>

      ??<bean?id="saodiseng"?class="com.cmower.java_demo.ioc.Xiaosan"?/>

      </beans>

      通過 元素配置了兩個(gè)對(duì)象,一個(gè)老王主持,一個(gè)小三和尚,使用 元素將小三和尚作為老王主持的構(gòu)造參數(shù)。

      準(zhǔn)備工作完成以后,我們來測(cè)試一下,代碼示例如下:
      public?class?Test?{

      ????public?static?void?main(String[]?args)?{
      ????????ApplicationContext?context?=?new?ClassPathXmlApplicationContext(
      "application.xml");
      ????????Laowang?laowang?=?(Laowang)?context.getBean("laowang");
      ????????laowang.mingling();
      ????}

      }

      你看,我們將控制權(quán)交給了 IoC 框架 Spring,這樣也可以完美的解決代碼耦合度較緊的問題。

      05、最后

      總結(jié)一下:

      1)控制反轉(zhuǎn)是一種在軟件工程中解耦合的思想,把控制權(quán)交給了第三方,在運(yùn)行的時(shí)候由第三方?jīng)Q定將具體的依賴對(duì)象“注入”到調(diào)用類的對(duì)象中。

      2)依賴注入可以作為控制反轉(zhuǎn)的一種實(shí)現(xiàn)方式,將實(shí)例變量傳入到一個(gè)對(duì)象中去。

      3)通過 IoC 框架,類 A 依賴類 B 的強(qiáng)耦合關(guān)系可以在運(yùn)行時(shí)通過容器建立,也就是說把創(chuàng)建 B 實(shí)例的工作移交給容器,類 A 只管使用就可以。

      ?

      友情鏈接
      ioDraw流程圖
      API參考文檔
      OK工具箱
      云服務(wù)器優(yōu)惠
      阿里云優(yōu)惠券
      騰訊云優(yōu)惠券
      京東云優(yōu)惠券
      站點(diǎn)信息
      問題反饋
      郵箱:[email protected]
      QQ群:637538335
      關(guān)注微信

        <ul id="qxxfc"><fieldset id="qxxfc"><tr id="qxxfc"></tr></fieldset></ul>
          日韩激情视频网站 | 青青草在线网址 | 中国乱伦一级大黄片 | 三上悠亚ed2k | 高潮小视频| 干人人 | 免费专区 - 色哟哟 | 高清毛片按摩性按摩 | 国产精品自拍视频在线 | 一级片免费 |