工廠模式——看這一篇就夠了
- 摘要:最近根據公司的業務需要,封裝了一些平時開發中基本都會用到的基礎業務模組,其中用的最多的就是各個工廠模式了,同時也趁著這個機會複習了一下工廠模式。這篇文章會詳細介紹一下各個工廠模式的優缺點,如果你能完全理解了以下三個例項那麼工廠模式就不在話下了。由於業務程式碼不能公開,文中用到的例項會使用其他例子代替。我們知道Java裡邊共有23種設計模式而工廠模式就有三種,它們分別是簡單工廠模式(並不在23中模式之中),工廠方法模式以及抽象工廠模式,其中我們通常所說的工廠模式指的是工廠方法模式
-
最近根據公司的業務需要,封裝了一些平時開發中基本都會用到的基礎業務模組,其中用的最多的就是各個工廠模式了,同時也趁著這個機會複習了一下工廠模式。這篇文章會詳細介紹一下各個工廠模式的優缺點,如果你能完全理解了以下三個例項那麼工廠模式就不在話下了。由於業務程式碼不能公開,文中用到的例項會使用其他例子代替。
我們知道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)系統結構穩定,不會頻繁的增加物件。(因為一旦增加就需要修改原有程式碼,不符合開閉原則)以上就是三種工廠模式的總結,如有不對之處還希望各位留言指正,以免誤導他人。