設計模式——工廠模式,看這一篇就夠了

原文鏈接:https://www.jianshu.com/p/83ef48ce635b

最近根據公司的業務需要,封裝了一些平時開發中基本都會用到的基礎業務模塊,其中用的最多的就是各個工廠模式了,同時也趁着這個機會複習了一下工廠模式。這篇文章會詳細介紹一下各個工廠模式的優缺點,如果你能完全理解了以下三個實例那麼工廠模式就不在話下了。由於業務代碼不能公開,文中用到的實例會使用其他例子代替。
  我們知道Java裏邊共有23種設計模式而工廠模式就有三種,它們分別是簡單工廠模式(並不在23中模式之中),工廠方法模式以及抽象工廠模式,其中我們通常所說的工廠模式指的是工廠方法模式,工廠方法模式是日常開發中使用頻率最高的一種設計模式,甚至在Android的源碼中也是隨處可見。
  下面按照學習的難易程度由淺入深的來說說這三種模式,每種模式都會先從定義,使用場景,實例三方面入手。很多小夥伴都說學習的時候感覺理解了,實例也能看得懂,可在實際開發中就不會運用了,這因爲沒有記住它的使用場景,各位小夥伴一定要結合實例記住使用場景,這樣才能在開發中達到融匯貫通的效果。這也說明了設計模式只是思想,沒有固定的代碼!
首先來看最簡單的。

簡單工廠模式

簡單工廠模式其實並不算是一種設計模式,更多的時候是一種編程習慣。

定義:
  定義一個工廠類,根據傳入的參數不同返回不同的實例,被創建的實例具有共同的父類或接口。

適用場景:
  其實由定義也大概能推測出其使用場景,首先由於只有一個工廠類,所以工廠類中創建的對象不能太多,否則工廠類的業務邏輯就太複雜了,其次由於工廠類封裝了對象的創建過程,所以客戶端應該不關心對象的創建。總結一下適用場景:
  (1)需要創建的對象較少。
  (2)客戶端不關心對象的創建過程。
以上就是簡單工廠模式簡單工廠模式的適用場景,下面看一個具體的實例。

實例:
  創建一個可以繪製不同形狀的繪圖工具,可以繪製圓形,正方形,三角形,每個圖形都會有一個draw()方法用於繪圖,不看代碼先考慮一下如何通過該模式設計完成此功能。

由題可知圓形,正方形,三角形都屬於一種圖形,並且都具有draw方法,所以首先可以定義一個接口或者抽象類,作爲這三個圖像的公共父類,並在其中聲明一個公共的draw方法。

public interface Shape {
    void draw();
}

這裏定義成抽象類也是可以的,只不過接口是更高一級的抽象,所以習慣定義成接口,而且接口支持多實現,方便以後擴展。

下面就是編寫具體的圖形,每種圖形都實現Shape 接口
圓形

public class CircleShape implements Shape {

    public CircleShape() {
        System.out.println(  "CircleShape: created");
    }

    @Override
    public void draw() {
        System.out.println(  "draw: CircleShape");
    }

}

正方形

public class RectShape implements Shape {
    public RectShape() {
       System.out.println(  "RectShape: created");
    }

    @Override
    public void draw() {
       System.out.println(  "draw: RectShape");
    }

}

三角形

public class TriangleShape implements Shape {

    public TriangleShape() {
        System.out.println(  "TriangleShape: created");
    }

    @Override
    public void draw() {
        System.out.println(  "draw: TriangleShape");
    }

}

下面是工廠類的具體實現

 public class ShapeFactory {
          public static final String TAG = "ShapeFactory";
          public static Shape getShape(String type) {
              Shape shape = null;
              if (type.equalsIgnoreCase("circle")) {
                  shape = new CircleShape();
              } else if (type.equalsIgnoreCase("rect")) {
                  shape = new RectShape();
              } else if (type.equalsIgnoreCase("triangle")) {
                  shape = new TriangleShape();
              }
              return shape;
          }
   }

在這個工廠類中通過傳入不同的type可以new不同的形狀,返回結果爲Shape 類型,這個就是簡單工廠核心的地方了。
客戶端使用

畫圓形

    Shape shape= ShapeFactory.getShape("circle");
    shape.draw();

畫正方形

    Shape shape= ShapeFactory.getShape("rect");
    shape.draw();

畫三角形

    Shape shape= ShapeFactory.getShape("triangle");
    shape.draw();

只通過給ShapeFactory傳入不同的參數就實現了各種形狀的繪製。以上就是簡單工廠方式,小夥伴們看明白了嗎?

工廠方法模式

工廠方法模式是簡單工廠的進一步深化, 在工廠方法模式中,我們不再提供一個統一的工廠類來創建所有的對象,而是針對不同的對象提供不同的工廠。也就是說每個對象都有一個與之對應的工廠。

定義:
  定義一個用於創建對象的接口,讓子類決定將哪一個類實例化。工廠方法模式讓一個類的實例化延遲到其子類。
  這次我們先用實例詳細解釋一下這個定義,最後在總結它的使用場景。

實例:
  現在需要設計一個這樣的圖片加載類,它具有多個圖片加載器,用來加載jpg,png,gif格式的圖片,每個加載器都有一個read()方法,用於讀取圖片。下面我們完成這個圖片加載類。

首先完成圖片加載器的設計,編寫一個加載器的公共接口。

public interface Reader {
    void read();
}

Reader 裏面只有一個read()方法,然後完成各個圖片加載器的代碼。

Jpg圖片加載器

public class JpgReader implements Reader {
    @Override
    public void read() {
        System.out.print("read jpg");
    }
}

Png圖片加載器

public class PngReader implements Reader {
    @Override
    public void read() {
        System.out.print("read png");
    }
}

Gif圖片加載器

public class GifReader implements Reader {
    @Override
    public void read() {
        System.out.print("read gif");
    }
}

現在我們按照定義所說定義一個抽象的工廠接口ReaderFactory

public interface ReaderFactory {
    Reader getReader();
}

裏面有一個getReader()方法返回我們的Reader 類,接下來我們把上面定義好的每個圖片加載器都提供一個工廠類,這些工廠類實現了ReaderFactory 。

Jpg加載器工廠

public class JpgReaderFactory implements ReaderFactory {
    @Override
    public Reader getReader() {
        return new JpgReader();
    }
}

Png加載器工廠

public class PngReaderFactory implements ReaderFactory {
    @Override
    public Reader getReader() {
        return new PngReader();
    }
}

Gif加載器工廠

public class GifReaderFactory implements ReaderFactory {
    @Override
    public Reader getReader() {
        return new GifReader();
    }
}

在每個工廠類中我們都通過複寫的getReader()方法返回各自的圖片加載器對象。

客戶端使用

讀取Jpg

ReaderFactory factory=new JpgReaderFactory();
Reader  reader=factory.getReader();
reader.read();

讀取Png

ReaderFactory factory=new PngReaderFactory();
Reader  reader=factory.getReader();
reader.read();

讀取Gif

ReaderFactory factory=new GifReaderFactory();
Reader  reader=factory.getReader();
reader.read();

可以看到上面三段代碼,分別讀取了不同格式的圖片,不同之處在於針對不同的圖片格式聲明瞭不同的工廠,進而創建了相應的圖片加載器。

通過這個實例各位小夥伴是不是對工廠模式有了進一步的理解呢,和簡單工廠對比一下,最根本的區別在於簡單工廠只有一個統一的工廠類,而工廠方法是針對每個要創建的對象都會提供一個工廠類,這些工廠類都實現了一個工廠基類(本例中的ReaderFactory )。下面總結一下工廠方法的適用場景。

適用場景:

(1)客戶端不需要知道它所創建的對象的類。例子中我們不知道每個圖片加載器具體叫什麼名,只知道創建它的工廠名就完成了牀架過程。
  (2)客戶端可以通過子類來指定創建對應的對象。
以上場景使用於採用工廠方法模式。

抽象工廠模式

這個模式最不好理解,而且在實際應用中侷限性也蠻大的,因爲這個模式並不符合開閉原則。實際開發還需要做好權衡。
  抽象工廠模式是工廠方法的進一步深化,在這個模式中的工廠類不單單可以創建一個對象,而是可以創建一組對象。這是和工廠方法最大的不同點。

定義:
  提供一個創建一系列相關或相互依賴對象的接口,而無須指定它們具體的類。( 在抽象工廠模式中,每一個具體工廠都提供了多個工廠方法用於產生多種不同類型的對象)
  
抽象工廠和工廠方法一樣可以劃分爲4大部分:
AbstractFactory(抽象工廠)聲明瞭一組用於創建對象的方法,注意是一組。
ConcreteFactory(具體工廠):它實現了在抽象工廠中聲明的創建對象的方法,生成一組具體對象。
AbstractProduct(抽象產品):它爲每種對象聲明接口,在其中聲明瞭對象所具有的業務方法。
ConcreteProduct(具體產品):它定義具體工廠生產的具體對象。
下面還是先看一個具體實例。

實例:
  現在需要做一款跨平臺的遊戲,需要兼容Android,Ios,Wp三個移動操作系統,該遊戲針對每個系統都設計了一套操作控制器(OperationController)和界面控制器(UIController),下面通過抽閒工廠方式完成這款遊戲的架構設計。

由題可知,遊戲裏邊的各個平臺的UIController和OperationController應該是我們最終生產的具體產品。所以新建兩個抽象產品接口。

抽象操作控制器

public interface OperationController {
    void control();
}

抽象界面控制器

public interface UIController {
    void display();
}

然後完成各個系統平臺的具體操作控制器和界面控制器
Android

public class AndroidOperationController implements OperationController {
    @Override
    public void control() {
        System.out.println("AndroidOperationController");
    }
}

public class AndroidUIController implements UIController {
    @Override
    public void display() {
        System.out.println("AndroidInterfaceController");
    }
}

Ios

public class IosOperationController implements OperationController {
    @Override
    public void control() {
        System.out.println("IosOperationController");
    }
}

public class IosUIController implements UIController {
    @Override
    public void display() {
        System.out.println("IosInterfaceController");
    }
}

Wp

public class WpOperationController implements OperationController {
    @Override
    public void control() {
        System.out.println("WpOperationController");
    }
}
public class WpUIController implements UIController {
    @Override
    public void display() {
        System.out.println("WpInterfaceController");
    }
}

下面定義一個抽閒工廠,該工廠需要可以創建OperationController和UIController

public interface SystemFactory {
    public OperationController createOperationController();
    public UIController createInterfaceController();
}

在各平臺具體的工廠類中完成操作控制器和界面控制器的創建過程

Android

public class AndroidFactory implements SystemFactory {
    @Override
    public OperationController createOperationController() {
        return new AndroidOperationController();
    }

    @Override
    public UIController createInterfaceController() {
        return new AndroidUIController();
    }
}

Ios

public class IosFactory implements SystemFactory {
    @Override
    public OperationController createOperationController() {
        return new IosOperationController();
    }

    @Override
    public UIController createInterfaceController() {
        return new IosUIController();
    }
}

Wp

public class WpFactory implements SystemFactory {
    @Override
    public OperationController createOperationController() {
        return new WpOperationController();
    }

    @Override
    public UIController createInterfaceController() {
        return new WpUIController();
    }
}

客戶端調用:

    SystemFactory mFactory;
    UIController interfaceController;
    OperationController operationController;

    //Android
    mFactory=new AndroidFactory();
    //Ios
    mFactory=new IosFactory();
    //Wp
    mFactory=new WpFactory();

    interfaceController=mFactory.createInterfaceController();
    operationController=mFactory.createOperationController();
    interfaceController.display();
    operationController.control();

針對不同平臺只通過創建不同的工廠對象就完成了操作和UI控制器的創建。小夥伴們可以對比一下,如果這個遊戲使用工廠方法模式搭建需要創建多少個工廠類呢?下面總結一下抽象工廠的適用場景。

適用場景:
(1)和工廠方法一樣客戶端不需要知道它所創建的對象的類。
(2)需要一組對象共同完成某種功能時。並且可能存在多組對象完成不同功能的情況。
(3)系統結構穩定,不會頻繁的增加對象。(因爲一旦增加就需要修改原有代碼,不符合開閉原則)

以上就是三種工廠模式的總結,如有不對之處還希望各位留言指正,以免誤導他人。



作者:Knight_Davion
鏈接:https://www.jianshu.com/p/83ef48ce635b
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯繫作者獲得授權並註明出處。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章