<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      Fork me on GitHub

      設計模式——從工廠方法模式到 IOC/DI思想

      回顧簡單工廠

      回顧:從接口的角度去理解簡單工廠模式

      前面說到了簡單工廠的本質是選擇實現,說白了是由一個專門的類去負責生產我們所需要的對象,從而將對象的創建從代碼中剝離出來,實現松耦合。我們來看一個例子:

      我們要創建一個文件導出工具

      public interface FileOper{
      
        public Boolean exceptFile(String data);
      }
      public class XMLFileOp implment FileOper{
      
         public Boolean exceptFile(String data){
            System.out.println("導出一個xml文件");
            return true;
         } 
      }
      public class Factory{
      
          public static FileOper createFileOp(){
      
              return new XMLFileOp();
          } 
      
      }
      public Class Test{
      
       public static void main(String args[]){
      
          FileOper op = Factory.createFileOp();
          op.exceptFile("測試");
      
      }
      
      
      }

      這樣看起來沒什么問題,那么我們既然做出來了這個結構,就是為了后續的擴展它,例子中只是為了實現XML文件的導出,后續,我們可以自己實現一個txt文件的導出類,只需要實現FileOper接口就好:

      public Class TxtFileOp implment FileOper{ 

      public Boolean ExceptFile(String data){
      System.out.println(
      "導出txt文件");
      return true
      }
      }

      這時候我們還是通過工廠來獲取這個對象,只需將Factory中追加一個else if 即可通過傳參來獲取想要的對象了。

      工廠方法模式

      仔細分析上面的場景,事實上在實現導出文件的業務邏輯中,它根本不知道要使用哪一種導出文件的格式,因此這個對象根本就不應該和具體導出文件的對象耦合在一起,它只需要面向導出文件接口(FileOper)就好,這是工廠的思想,我們上面用簡單工廠沒錯啊,但是后面又加入了新的擴展

      這樣一來,又有新的問題,面對新的類,簡單工廠便不能提供動態的擴展,必須要去修改內部的代碼,破壞了開閉原則。我們上一篇也提到了,簡單工廠也有它自身的缺陷,其中最嚴重的就是,它雖然對依賴對象的主體實現了解耦,可是它本身內部卻耦合較為嚴重。這時候我們可以看看工廠方法模式了,工廠方法模式的思路很有意思:老子不管了!采取無為而治的方式。不是需要接口對象么,那就定義一個方法來創建,可是事實上它自己是不知道如何創建這個接口對象的,不過這不重要,定義成抽象方法就行了,交給子類去實現,老子欠債,兒子你來還。

      工廠方法的結構

      Product:工廠方法所創建的具體對象的統一接口。

      Factory:為該類產品的抽象工廠,其內部有聲明的工廠方法,工廠方法多為抽象方法,且返回一個Product對象

      ProductOne:為具體的產品,也就是Product的具體實現類,真正的工廠產物。

      SpecificFactory:具體的工廠,用于生產指定類型的Product,例如圖中它只負責生產 ProductOne這個對象。

      工廠方法模式的樣例代碼

      public class AbstractFactoryTest {
          public static void main(String[] args) {
              try {
                  Product a;
                  AbstractFactory af;
                  af = (AbstractFactory) ReadXML1.getObject();
                  a = af.newProduct();
                  a.show();
              } catch (Exception e) {
                  System.out.println(e.getMessage());
              }
          }
      }
      //抽象產品:提供了產品的接口
      interface Product {
          public void show();
      }
      //具體產品1:實現抽象產品中的抽象方法
      class ConcreteProduct1 implements Product {
          public void show() {
              System.out.println("具體產品1顯示...");
          }
      }
      //具體產品2:實現抽象產品中的抽象方法
      class ConcreteProduct2 implements Product {
          public void show() {
              System.out.println("具體產品2顯示...");
          }
      }
      //抽象工廠:提供了廠品的生成方法
      interface AbstractFactory {
          public Product newProduct();
      }
      //具體工廠1:實現了廠品的生成方法
      class ConcreteFactory1 implements AbstractFactory {
          public Product newProduct() {
              System.out.println("具體工廠1生成-->具體產品1...");
              return new ConcreteProduct1();
          }
      }
      //具體工廠2:實現了廠品的生成方法
      class ConcreteFactory2 implements AbstractFactory {
          public Product newProduct() {
              System.out.println("具體工廠2生成-->具體產品2...");
              return new ConcreteProduct2();
          }
      }

        基于XML解析的外部配置文件

      class ReadXML1 {
          //該方法用于從XML配置文件中提取具體類類名,并返回一個實例對象
          public static Object getObject() {
              try {
                  //創建文檔對象
                  DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
                  DocumentBuilder builder = dFactory.newDocumentBuilder();
                  Document doc;
                  doc = builder.parse(new File("src/FactoryMethod/config1.xml"));
                  //獲取包含類名的文本節點
                  NodeList nl = doc.getElementsByTagName("className");
                  Node classNode = nl.item(0).getFirstChild();
                  String cName = "FactoryMethod." + classNode.getNodeValue();
                  //System.out.println("新類名:"+cName);
                  //通過類名生成實例對象并將其返回
                  Class<?> c = Class.forName(cName);
                  Object obj = c.newInstance();
                  return obj;
              } catch (Exception e) {
                  e.printStackTrace();
                  return null;
              }
          }
      }

      上面是一個較為初級也較為經典的工廠方法模板,工廠方法還有另一種用法,即抽象的工廠父類除了創建對象的方法之外,還包含其他的一些方法,而工廠父類通常使用這些方法來完成某些任務,下面我們來看看這第二種表現方式。

       工廠方法模式實現文件導出

      根據上面工廠方法模式提供的思路,我們重新來思考并實現一下一開始那個文件導出的功能。

      /**
       * 文件導出接口
       * 實現將指定數據的導出
       * 擴展:實現該接口,可指定生產具體文件類型
       * @author GCC
       */
      public interface ExportFileApi {
      
          /**
           * 導出文件
           * @param data 待導出數據
           * @return boolean
           */
          boolean exportFile(String data);
      
      }
      /**
       * 生產Excel文件導出器
       * @author GCC
       */
      public class ExportExcelFile implements ExportFileApi {
          @Override
          public boolean exportFile(String data) {
              //todo 處理數據
              return false;
          }
      }
      /**
       * 導出功能口,工廠
       * @author GCC
       */
      public abstract class ExportFileOperate {
      
          public Logger logger = Logger.getLogger(ExportFileOperate.class);
          //使用產品對象來實現一定功能的方法,這里是實現數據導出
          public void export(String data){
              ExportFileApi exportoper = methodFactory();
              if(exportoper.exportFile(data)){
                  logger.info("文件導出成功");
                  return;
              }
              logger.error("文件導出失敗");
      
          }
      
          //工廠方法
          protected abstract ExportFileApi;
      
      }
      /**
       * 將指定數據導出為Excel文件
       * @author GCC
       */
      public class ExportExcelFileFactory extends ExportFileOperate {
      
          @Override
          protected ExportFileApi methodFactory() {
              return new ExportExcelFile();
          }
      }
      /**
       * 客戶用例
       */
      public class App 
      {
          static Logger logger = Logger.getLogger(App.class);
      
          public static void main( String[] args )
          {
              ExportFileOperate ex = new ExportExcelFileFactory();
              ex.export("測試數據");
          }
      }

       

      這里大家可能會 有疑惑,你這個實現方式怎么和前面提到的工廠方法模式的標準樣例不一樣? 其實這是工廠方法模式的另一種結構,確切地說這才是真正意義上的工廠方法模式(上面的模板只是工廠方法的正常形態)。

      這一種的實現方式是 :父類會是一個抽象類,里面包含創建所需對象的抽象方法(代碼樣例中ExportFileOperat類的methodFactory()方法,這里ExportFileOperat類就是所謂的工廠類,需要補充的是設計模型的使用,不要拘泥于命名名稱,可以根據實際需求來進行相應的變化),這些抽象方法就是工廠方法模式中的工廠方法。父類里面,通常會有使用這些產品對象來實現一定的功能的方法(代碼樣例中ExportFileOperat類的export()方法)。而這些方法所實現的功能通常都是公共功能,不管子類選擇了何種具體的產品實現,這些方法總能正常運行。

      之所以會有上面兩種方式,主要原因在于工廠方法對于客戶端的支持,這里需要弄清楚一個問題,誰在使用工廠方法所創建的對象?

      事實上,在工廠方法模式里,應該是工廠中的其他方法來使用工廠所創建的對象,為了方便,工廠方法創建的對象也可直接提供給外部的客戶端來調用,但工廠方法的本意是由Factory抽象父類內部的方法來使用工廠方法創建的對象。

      以下這幅時序圖,即說明了客戶端調用factory的兩種方式。

      其實客戶端應該使用Factory對象,或者是由Factory所創建出來的產品對象,對于客戶端使用Factory對象,這個時候工廠方法創建的對象,是Factory中的某些方法在用,對于使用那些由Factory創建出來的對象,這個時候工廠方法創建的對象,是構成客戶端所需對象的一部分。

      工廠方法與簡單工廠的區別

      下面我們看一個例子,這里我打算做個計算器,如果用簡單工廠模式來做,它的結構是這樣的:

      public class SimpleFactory {
          public Calculator create(String type){
      
              switch (type){
                  case "+":
                      //返回一個具有加法功能的計算器對象
                      return new AddCalculator();
                  case "-":
                      //返回一個具有減法功能的計算器對象
                      return new DeCalculator();
                  default:return null;
              }
          }
      }

       

      為了工廠更完整,采用傳參的靜態工廠方式來實現,這樣我簡單工廠里將通過Switch語句來管控生產哪一種計算類,這時候,突然來了新的需求,我需要一個乘法的功能,這時候我就得實現計算器接口,完成一個乘法類,同時去簡單工廠的代碼里,追加一個case。

      同理,我使用工廠方法的模式來做這個功能,這塊的類圖則如上圖一樣,我的工廠代碼里不需要Switch了,只需要一個具有生產計算器對象的抽象方法的抽象工廠類即可,當我需要一個乘法能力的計算器時,實現計算器接口,完成乘法類,然后繼承抽象工廠,完成一個乘法的工廠子類,然后再用乘法的工廠子類來創建乘法類。然后再去修改客戶端。

      上面一對比,嘿,這升級版的工廠方法怎么比簡單工廠還復雜了!?肯定很多同學在看工廠設計模式的時候很困惑,簡單工廠和工廠方法的區別在哪,明明感覺用簡單工廠更方便呢?

      其實回頭好好看看設計原則,就會發現,這是一個解耦的過程,簡單工廠模式最大的優點在于工廠類中包含了必要的邏輯判斷,根據客戶的選擇動態的實例化相關的產品類,對于客戶端來說,除去了與具體產品對象的依賴。但問題就是隨著你的新需求,如果使用簡單工廠,那么你就不得不去破壞開閉原則,而看起來改動更為復雜的工廠方法模式,你并不需要對以前的代碼進行改動,只需要繼承,擴展即可。仔細觀察一下,簡單工廠是讓客戶端與依賴對象進行解耦,而工廠方式模式又是對工廠的一層解耦,原本內部耦合性較強的if else,變成了由客戶端或者配置文件來控制,工廠方法將簡單工廠內部的邏輯判斷移到了使用它的外部(客戶端或者配置文件)來控制。本來擴展是需要修改工廠類源代碼的,現在變成了客戶端修改調用或者配置文件中的一個參數。

      工廠方法模式的意義

      工廠方法模式的主要思想是讓父類在不知情的情況下,完成自身功能的調用,而具體的實現則延遲到子類來做;或者說是在靜態工廠中,將其原本耦合的if else抽離出來,配合配置文檔使用,將寫死的if else靈活實現(配置文件并不是默認必須要有的)。這樣在設計的時候,不用去考慮具體的實現,需要某個對象,把它通過工廠方法返回就好,在使用這些對象實現功能的時候還是通過接口來操作,這里就有一點IOC的韻味了。

      工廠方法模式與IOC、DI

      什么是IOC/DI?

      想想之前沒有學習設計模式,剛學會使用Java就被Spring的bean配置文件支配的恐懼。

      那時候你說自己學Java,對方一定會問你Spring,說到Spring,肯定避不開“什么是IOC,什么是DI?”這個讓人頭痛的問題,那么,到底什么是IOC,DI?

      看完工廠的設計思想,對這個問題才開始了真正的思考。

      IOC——控制反轉

      DI——依賴注入

      除了上面脫口而出的回答,我想我們這些面向對象的程序猿們,應該有個更深入的理解,到底什么是控制反轉,什么是依賴注入。要想理解上面兩個概念,必須把問題拆開來看,先搞清楚基本的問題幾個問題:

      主客體是誰,或者說參與這個概念的都有誰?

      什么叫依賴?為什么會有依賴?

      什么叫注入?注入的是什么?誰注入誰?

      控制反轉,誰控制誰,控制的是什么,既然叫反轉,正轉是啥?

      下面我們一個個來解決問題:

      1、參與者,說起參與者,一般我們在這個概念中是有三個參與者,具體某個類,容器,某個對象所依賴的外部資源(另一個對象),就好比我有三個類,A,B,C,A對象我們把它想象成一個客戶端,B是它需要的一個外部的資源,C是一個叫容器的第三方。

      2、什么叫依賴,這個就比較好說了,你有一個A類,但是你A類的成員變量有一個是B類的實例聲明,那么A就依賴于B,也就是說,A如果想正常運轉(或者說功能正常),必須得依賴于它的成員變量B,至于為什么會有依賴,那也好理解了,面向對象就是將功能封裝,每個對象都功能單一,這樣有些復雜的對象需要實現復雜的功能,就必須需要其他類的協同。

      3、注入,就是說,A你的成員變量B只是聲明了一個變量,它對于對象A來說,只是一個引用,一個字符,本身并沒有實體,你可以new 一下這個變量的構造函數,才能使這個變量真正有靈魂,又或者用它來承接外部傳進來的同類實體,這里外部傳進來B的方式就叫注入,注入的是這個變量類型 具體的實例化對象。誰來注入,當然是容器C來注入給A,將B注入給A

      4、簡單來說就是容器來控制A,控制的就是A所依賴的對象B實例的創建,反轉是與正轉對應來說的,什么是正轉呢,A類中有個對象B的成員變量,正常情況下,A類中功能用到B對象的時候,A要主動去獲取一個B對象,例如new一下,這種情況被稱為正向的。這樣就比較好理解反轉了,A不再去主動獲取B對象了,而是被動的等待B的到來(注入),等待容器C獲取一個B的實例,然后反向的注入進A。

       

       

      所以,綜上來看,控制反轉和依賴注入其實說的是同一件事,說白了就是對象創建這個責任歸誰的問題,依賴注入是從應用程序的角度去描述,應用程序依賴外部容器去創建并注入它所需要的外部資源對象。控制反轉是從容器的角度出發,容器控制應用程序,由容器反向地向應用程序注入其所需要的外部對象

       

      其實IOC/DI并不是一種代碼實現,更多的它是一種思想,它從思想上完成了 “主從換位” 的變化,應用程序本來是主體,占絕對地位,它需要什么都會主動出擊去獲取,過強的控制欲導致了它耦合過重,而在IOC/DI思想中,應用程序變成被動的等待容器的注入,需要啥只能提出來,什么時候給,給什么樣子的,主動權完全交給了容器,較強的實現了解耦,程序的靈活性也就高了

       

       工廠方法與IOC/DI思想

      從某個角度來看,工廠方法模式跟IOC/DI的思想很貼近。

      上面也說過了,IOC/DI就是讓應用程序不再主動獲取外部資源,而是被動等待第三方的注入,那么在編寫程序的時候,一旦遇到需要外部資源的地方,就會開一個窗口,提供給容器一個注入的途徑,讓容器注入進來,細節這里就不過多贅述了,自己去找Spring聊吧。  下面用IOC/DI和工廠方法來實現一個樣例對比一下。

      用IOC/DI來實現一個類Person:

      public class Person {
      
          private String name;
          //依賴文件操作對象
          private FileUtil fileUtil;
      
          private int age;
      
          //提供set方法,供外部注入
          public void setFileUtil(FileUtil fileUtil){
              this.fileUtil = fileUtil;
          }
          
          public void opFile(String fileurl){
              fileUtil.createFile(fileurl);
          }
          
      
      }

      這就是IOC/DI思想來實現的一個類,我依賴FileUtil,沒事,我不管,我提供給你一個set的注入途徑,剩下的我不管了,我就默認我用FileUtil的時候,它是真真切切存在在堆中的對象。(本質是當外部的容器,創建Person對象的時候,會發現它依賴FileUtil,然后容器去獲取一個FileUtil,通過Person提供的Set方法,將獲取的FileUtil對象注入進去,然后一個完整的Person對象就被制造出來了,這個過程Person角度來看,Person是無感的)

       

      下面用工廠方法來搞上面的例子:

      public abstract class Person {
      
          private String name;
      
          private int age;
      
          //交給子類去實現我的依賴
          public abstract FileUtil getFileutil();
      
          public void opFile(String fileurl){
              getFileutil().createFile(fileurl);
          }
      
      
      }

      這里,Person類也是需要用到FileUtil,但是它也不需要主動的去new一下FileUtil,而是通過抽象方法的形式,將FileUtil的實例化延申到子類去實現,其實就是變相地提供了一種注入渠道(標準bean中是通過set方法,容器調用Set方法注入需要的對象,而工廠方法則是通過實現子類,即讓子類來完成依賴對象的注入)

       

      仔細體會這兩種寫法,對比他們的實現,在思想層面來看,會發現,工廠方法模式和IOC/DI的思想是相似的,都是“主動變被動”,“主位換從位”,從而獲得了更加靈活的程序結構。

       

       

       

      設計模式匯總目錄

       

      posted @ 2021-03-30 09:50  糖拌西紅柿  閱讀(909)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 4480yy亚洲午夜私人影院剧情| 国产视色精品亚洲一区二区| 欧美性猛交xxxx乱大交丰满| 亚洲高清aⅴ日本欧美视频| 年轻女教师hd中字3| 白丝乳交内射一二三区| 精品人妻伦九区久久aaa片69 | 中文字幕精品久久久久人妻红杏1 人妻少妇精品中文字幕 | 国产精品国三级国产av| 欧美日韩在线视频| 自拍偷亚洲产在线观看| 麻豆国产成人AV在线播放| 国产亚洲综合一区二区三区| 国产视频精品一区 日本| 午夜欧美日韩在线视频播放 | 亚洲欧洲一区二区免费| 无码一区二区三区中文字幕| 免费观看激色视频网站| 国产一区二区午夜福利久久| 亚洲av无码牛牛影视在线二区| 中文字幕一区二区网站| 日本久久99成人网站| 亚洲AV无码破坏版在线观看| 国产一级黄色片在线观看| 午夜国产理论大片高清| 天天躁夜夜躁av天天爽| 国产欧美日韩va另类在线播放| 亚洲精品天堂在线观看| 国产成人精品亚洲精品密奴| 久久夜色撩人精品国产av| 日本一区二区三区在线看| 亚洲精品午夜国产VA久久成人 | 免费极品av一视觉盛宴| 亚洲人成色99999在线观看| 99蜜桃在线观看免费视频网站 | 国产精品香港三级国产av| 无码人妻熟妇av又粗又大| 亚洲天堂成人一区二区三区| 激情亚洲专区一区二区三区| 国产在线视频导航| 波多野结av衣东京热无码专区|