乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      設計模式 - 工廠模式

       印度阿三17 2019-09-30

      概述

      我們都知道Java中共有 23 種設計模式,其中工廠模式分為三種,即:簡單工廠模式(不在 23 種設計模式之列)、工廠方法模式和抽象工廠模式;我們平時說的工廠模式,其實大都指工廠方法模式,這種模式是我們平時編碼中用的頻率最高的一種,在Spring源碼中就有很多工廠模式的應用,比如 BeanFactory。

      下面依次按照簡單工廠模式、工廠方法模式、抽象工廠模式的順序,依次由淺入深說說這三種模式;文章分別從定義、場景、優(yōu)缺點也示例進行講解。

      簡單工廠模式

      定義

      簡單工廠模式(Simple Factory Pattern)是指由一個工廠對象決定創(chuàng)建出哪一種產(chǎn)品類的實例,簡單來說就是,
      定義一個工廠類,根據(jù)傳入的參數(shù)不同返回不同的實例,被創(chuàng)建的實例具有共同的父類或接口。

      場景

      簡單工廠適用于工廠類負責創(chuàng)建的對象較少的場景,且客戶端只需要傳入工廠類的參數(shù),對于如何創(chuàng)建對象的邏輯不需要關心。總結一下就是:

      1. 需要創(chuàng)建的對象較少;

      2. 客戶端不關心對象的創(chuàng)建過程;

      優(yōu)缺點

      優(yōu)點

      實現(xiàn)了對責任的分割,提供了專門的工廠類用于創(chuàng)建對象

      缺點

      工廠類的職責相對過重,不易于擴展過于復雜的產(chǎn)品結構,不符合開閉原則(可解決)

      示例

      接下來我們構造一個場景來看看簡單工廠模式的應用:現(xiàn)在手機更新?lián)Q代的比較快,手機廠商每年基本都會在不同時間或者在同一時間發(fā)布生產(chǎn)不同型號和配置的手機。

      假設某手機公司最近發(fā)布了型號為 A、B 的手機,其中生產(chǎn)任務交給代工廠去生產(chǎn);我們都知道不管什么類型的手機都屬于手機,所以我們先創(chuàng)建一個手機類Phone,并在其中聲明一個公共的手機型號方法type

      /**
       * @author eamon.zhang
       * @date 2019-09-27 上午10:55
       */
      public interface Phone {
          void type();
      }

      然后定義具體的手機類型:

      型號 A:

      /**
       * @author eamon.zhang
       * @date 2019-09-27 上午11:02
       */
      public class PhoneA implements Phone {
          @Override
          public void type() {
              System.out.println("型號為A的手機!");
          }
      }

      型號 B:

      /**
       * @author eamon.zhang
       * @date 2019-09-27 上午11:03
       */
      public class PhoneB implements Phone {
          @Override
          public void type() {
              System.out.println("型號為B的手機!");
          }
      }

      創(chuàng)建手機代工廠 PhoneFactory 類:

      /**
       * @author eamon.zhang
       * @date 2019-09-27 上午10:54
       */
      public class PhoneFactory {
          public Phone product(String type) {
              switch (type) {
                  case "A":
                      return new PhoneA();
                  case "B":
                      return new PhoneB();
                  default:
                      return null;
              }
          }
      }

      測試:

      /**
       * @author eamon.zhang
       * @date 2019-09-27 上午11:09
       */
      public class PhoneFactoryTest {
      
          @Test
          public void product() {
              PhoneFactory phoneFactory = new PhoneFactory();
              phoneFactory.product("A").type();
      
              phoneFactory.product("B").type();
          }
      }

      輸出:

      型號為A的手機!
      型號為B的手機!

      當然,為了方便調用,PhoneFactory 中的product()也可以寫成靜態(tài)的。

      類圖:

      拓展

      解決不符合開閉原則問題

      上面的示例中,客戶端調用是簡單了,但如果我們業(yè)務繼續(xù)擴展,增加一個型號 C,那么上面的工廠方法中的product() 方法就得再次修改邏輯。不符合開閉原則;因此我們客戶考慮對其進行進一步優(yōu)化,利用反射技術修改product()方法:

       public Phone product(String className) {
          try {
              if (!(null == className || "".equals(className))) {
                  return (Phone) Class.forName(className).newInstance();
              }
          } catch (Exception e) {
              e.printStackTrace();
          }
          return null;
      }

      修改客戶端調用代碼:

      public void product() {
          PhoneFactory phoneFactory = new PhoneFactory();
          phoneFactory.product("com.eamon.javadesignpatterns.factory.PhoneA").type();
      
          phoneFactory.product("com.eamon.javadesignpatterns.factory.PhoneB").type();
      }

      經(jīng)過優(yōu)化之后,今后再增加型號,就不用去修改工廠方法了;但是又有一個問題,方法參數(shù)是很長的字符串,可控性有待提升,而且還需要強制轉型,不方便閱讀和維護,所以進一步改造:

      public Phone product(Class<? extends Phone> clazz) {
          try {
              if (null != clazz) {
                  return clazz.newInstance();
              }
          } catch (Exception e) {
              e.printStackTrace();
          }
          return null;
      }

      優(yōu)化客戶端調用代碼:

      @Test
      public void product() {
          PhoneFactory phoneFactory = new PhoneFactory();
          phoneFactory.product(PhoneA.class).type();
      
          phoneFactory.product(PhoneB.class).type();
      }

      再來看一下類圖:


      其他

      簡單工廠模式在 JDK 源碼中也無處不足,比如常用的 Calendar類中Calendar.getInstance()方法,跟進源碼到createCalendar(TimeZone zone,Locale aLocale)就可以看出。

      還有就是 常用的logback,我們可以看到 LoggerFactory 中有多個重載的方法 getLogger():

       public static Logger getLogger(String name) {
          ILoggerFactory iLoggerFactory = getILoggerFactory();
          return iLoggerFactory.getLogger(name);
      }
      
      public final Logger getLogger(final Class<?> clazz) {
          return getLogger(clazz.getName());
      }

      工廠方法模式

      定義

      工廠方法模式(Fatory Method Pattern)是指定義一個創(chuàng)建對象的接口,但讓實現(xiàn)這個 接口的類來決定實例化哪個類,工廠方法讓類的實例化推遲到子類中進行。

      在工廠方法模式中用戶只需要關心所需產(chǎn)品對應的工廠,無須關心創(chuàng)建細節(jié),而且加入新的產(chǎn)品符 合開閉原則。

      工廠方法模式主要解決產(chǎn)品擴展的問題,在簡單工廠中,隨著產(chǎn)品鏈的豐富,如果每個手機的創(chuàng)建邏輯有區(qū)別的話,工廠的職責會變得越來越多,有點像萬能工廠,并不便于維護。根據(jù)單一職責原則我們將職能繼續(xù)拆分,專人干專事。

      場景

      工廠方法適用于以下場景:

      1. 創(chuàng)建對象需要大量重復的代碼。

      2. 客戶端(應用層)不依賴于產(chǎn)品類實例如何被創(chuàng)建、實現(xiàn)等細節(jié)。

      3. 一個類通過其子類來指定創(chuàng)建哪個對象。

      優(yōu)缺點

      優(yōu)點

      1. 具有良好的封裝性,代碼結構清晰,井底了模塊間的耦合。

      2. 拓展性非常優(yōu)秀。(在增加產(chǎn)品類的情況下,只要修改具體的工廠類或擴展一個工廠類)

      3. 屏蔽了產(chǎn)品類。(產(chǎn)品類的實現(xiàn)如何變化,調用者不需要關心)

      缺點:

      1、類的個數(shù)容易過多,增加復雜度。
      2、增加了系統(tǒng)的抽象性和理解難度。

      示例

      A 型號手機由PhoneA工廠創(chuàng)建,B 型號手機由PhoneB工廠創(chuàng)建,對工廠本身也做一個抽象。來看代碼,先創(chuàng)建 PhoneFactory 接口:

      /**
       * @author eamon.zhang
       * @date 2019-09-27 下午1:45
       */
      public interface PhoneFactory {
         Phone product();
      }

      分別創(chuàng)建子工廠 PhoneAFactory

      /**
       * @author eamon.zhang
       * @date 2019-09-27 下午1:50
       */
      public class PhoneAFactory implements PhoneFactory {
          @Override
          public Phone product() {
              return new PhoneA();
          }
      }

      PhoneBFactory 類:

      /**
       * @author eamon.zhang
       * @date 2019-09-27 下午1:50
       */
      public class PhoneBFactory implements PhoneFactory {
          @Override
          public Phone product() {
              return new PhoneB();
          }
      }

      看測試代碼:

      /**
       * @author eamon.zhang
       * @date 2019-09-27 下午1:54
       */
      public class PhoneFactoryTest {
      
          @Test
          public void product() {
              PhoneFactory factory = new PhoneAFactory();
              factory.product().type();
      
              factory = new PhoneBFactory();
              factory.product().type();
      
          }
      }

      測試結果:

      型號為A的手機!
      型號為B的手機!

      再看一下類圖:

      拓展

      再來看看 logback 中工廠方法模式的應用,看看類圖就 OK 了:


      抽象工廠模式

      定義

      抽象工廠模式(Abastract Factory Pattern)是指提供一個創(chuàng)建一系列相關或相互依賴對象的接口,無需指定他們具體的類。

      客戶端(應用層)不依賴于產(chǎn)品類實例如何被創(chuàng)建、實現(xiàn)等細節(jié)。強調的是一系列相關的產(chǎn)品對象(屬于同一產(chǎn)品族)一起使用創(chuàng)建對象需要大量重復的代碼。需要提供一個產(chǎn)品類的庫,所有的產(chǎn)品以同樣的接口出現(xiàn),從而使客戶端不依賴于具體實現(xiàn)。

      理解

      為了便于大家理解抽象工廠,我們先了解兩個概念產(chǎn)品等級結構和產(chǎn)品族,看下面的圖:

      從上圖中看出有正方形,圓形和三角形三種圖形,相同顏色深淺的就代表同一個產(chǎn)品族,相同形狀的代表同一個產(chǎn)品等級結構。同樣可以從生活中來舉例,比如,美的電器生產(chǎn)多種家用電器。那么上圖中,顏色最深的正方形就代表美的洗衣機、顏色最深的圓形代表美的空調、顏色最深的三角形代表美的熱水器,顏色最深的一排都屬于美的品牌,都是美的電器這個產(chǎn)品族。再看最右側的三角形,顏色最深的我們指定了代表美的熱水器,那么第二排顏色稍微淺一點的三角形,代表海信的熱水器。同理,同一產(chǎn)品結構下還有格力熱水器,格力空調,格力洗衣機。

      再看下面這張圖,最左側的箭頭代表具體的工廠,有美的工廠、海信工廠、格力工廠。每個品牌的工廠都生產(chǎn)洗衣機、熱水器、空調。

      通過上面兩張圖的對比理解,相信大家對抽象工廠有了非常形象的理解。

      場景

      一個對象族(或是一組沒有任何關系的對象)都有相同的約束,則可以使用抽象工廠模式。簡單來說:

      1. 和工廠方法一樣客戶端不需要知道它所創(chuàng)建的對象的類。

      2. 需要一組對象共同完成某種功能時。并且可能存在多組對象完成不同功能的情況。

      3. 系統(tǒng)結構穩(wěn)定,不會頻繁的增加對象。(因為一旦增加就需要修改原有代碼,不符合開閉原則)

      優(yōu)缺點

      優(yōu)點

      • 封裝性,每個產(chǎn)品的實現(xiàn)類不是高層模塊要關心的,它要關心的是接口,不關心對象是如何創(chuàng)建的,只要知道工廠類是誰,就能創(chuàng)建出一個需要的對象,省時省力。

      • 產(chǎn)品族內(nèi)的約束為非公開狀態(tài)。

      缺點

      • 規(guī)定了所有可能被創(chuàng)建的產(chǎn)品集合,產(chǎn)品族中擴展新的產(chǎn)品困難,需要修改抽象工廠的接口

      • 增加了系統(tǒng)的抽象性和理解難度

      示例

      比如現(xiàn)在有一個應用,假如是某視頻軟件,需要在三個不同的平臺(Windows、IOS、Android)上運行,該應用針對每套系統(tǒng)都設計了一套上傳控制器(UploadController)、播放控制(DisplayController),下面通過抽象工廠模式來設計該軟件。

      視頻軟件里邊的各個平臺的UploadControllerDisplayController應該是我們最終生產(chǎn)的具體產(chǎn)品。所以新建兩個抽象產(chǎn)品接口。

      UploadController 接口:

      /**
       * @author eamon.zhang
       * @date 2019-09-27 下午2:59
       */
      public interface UploadController {
          void upload();
      }

      DisplayController 接口:

      /**
       * @author eamon.zhang
       * @date 2019-09-27 下午2:59
       */
      public interface DisplayController {
          void display();
      }

      定義抽象工廠VideoPlayerFactory類,它能夠創(chuàng)建UploadControllerDisplayController

      /**
       * 抽象工廠是主入口,在Spring中應用的最廣泛的一種設計模式,易于擴展
       *
       * @author eamon.zhang
       * @date 2019-09-27 下午3:04
       */
      public interface VideoPlayerFactory {
          DisplayController createDisplayController();
      
          UploadController createUploadController();
      }

      然后在各個平臺創(chuàng)建具體的 UploadControllerDisplayController

      創(chuàng)建適用于WindowsUploadControllerDisplayController

      /**
       * @author eamon.zhang
       * @date 2019-09-27 下午3:09
       */
      public class WindowsUploadController implements UploadController {
          @Override
          public void upload() {
              System.out.println("Windows 上傳控制器!");
          }
      }
      
      /**
       * @author eamon.zhang
       * @date 2019-09-27 下午3:09
       */
      public class WindowsDisplayController implements DisplayController {
      
          @Override
          public void display() {
              System.out.println("Windows 上的播放器!");
          }
      }

      創(chuàng)建適用于IOSUploadControllerDisplayController

      /**
       * @author eamon.zhang
       * @date 2019-09-27 下午3:10
       */
      public class IosUploaderController implements UploadController {
          @Override
          public void upload() {
              System.out.println("IOS 上傳控制器!");
          }
      }
      
      /**
       * @author eamon.zhang
       * @date 2019-09-27 下午3:09
       */
      public class IosDisplayController implements DisplayController {
      
          @Override
          public void display() {
              System.out.println("IOS 上的播放器!");
          }
      }

      創(chuàng)建適用于AndroidUploadControllerDisplayController

      /**
       * @author eamon.zhang
       * @date 2019-09-27 下午3:10
       */
      public class AndroidUploaderController implements UploadController {
          @Override
          public void upload() {
              System.out.println("Android 上傳控制器!");
          }
      }
      
      /**
       * @author eamon.zhang
       * @date 2019-09-27 下午3:09
       */
      public class AndroidDisplayController implements DisplayController {
      
          @Override
          public void display() {
              System.out.println("Android 上的播放器!");
          }
      }

      在各平臺具體的工廠類中完成上傳控制器和播放控制器的創(chuàng)建過程:

      創(chuàng)建WindowsFactory類:

      /**
       * @author eamon.zhang
       * @date 2019-09-27 下午3:15
       */
      public class WindowsFactory implements VideoPlayerFactory {
          @Override
          public DisplayController createDisplayController() {
              return new WindowsDisplayController();
          }
      
          @Override
          public UploadController createUploadController() {
              return new WindowsUploadController();
          }
      }

      創(chuàng)建IosFactory類:

      /**
       * @author eamon.zhang
       * @date 2019-09-27 下午3:17
       */
      public class IosFactory implements VideoPlayerFactory {
          @Override
          public DisplayController createDisplayController() {
              return new IosDisplayController();
          }
      
          @Override
          public UploadController createUploadController() {
              return new IosUploaderController();
          }
      }

      創(chuàng)建AndroidFactory類:

      /**
       * @author eamon.zhang
       * @date 2019-09-27 下午3:18
       */
      public class AndroidFactory implements VideoPlayerFactory {
          @Override
          public DisplayController createDisplayController() {
              return new AndroidDisplayController();
          }
      
          @Override
          public UploadController createUploadController() {
              return new AndroidUploaderController();
          }
      }

      來看客戶端調用:

      /**
       * @author eamon.zhang
       * @date 2019-09-27 下午3:20
       */
      public class VideoPlayerFactoryTest {
      
          @Test
          public void VideoPlayer() {
              VideoPlayerFactory factory = new WindowsFactory();
      
              // IOS
      //        factory = new IosFactory();
      //        // Android
      //        factory = new AndroidFactory();
      
              UploadController uploadController = factory.createUploadController();
              DisplayController displayController = factory.createDisplayController();
      
              uploadController.upload();
              displayController.display();
      
          }
      }

      以調用 Windows 為例,結果:

      Windows 上傳控制器!
      Windows 上的播放器!

      上面就是針對不同平臺只通過創(chuàng)建對應的工廠對象就完成了上傳控制器和播放控制器的創(chuàng)建。抽象工廠非常完美清晰地描述這樣一層復雜的關系。但是,不知道大家有沒有發(fā)現(xiàn),如果我們再繼續(xù)擴展功能,將下載器也加入到產(chǎn)品中,那么我們的代碼從抽象工廠,到具體工廠要全部調整,很顯然不符合開閉原則。因此就有了上面優(yōu)缺點中所說的缺點。


      總結

      在實際應用中,我們千萬不能犯強迫癥甚至有潔癖。在實際需求中產(chǎn)品等級結構升級是非常正常的一件事情。我們可以根據(jù)實際情況,只要不是頻繁升級,可以不遵循開閉原則。代碼每半年升級一次或者每年升級一次又有何不可呢?

        本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報。
        轉藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多