最近根據(jù)公司的業(yè)務(wù)需要,封裝了一些平時(shí)開發(fā)中基本都會(huì)用到的基礎(chǔ)業(yè)務(wù)模塊,其中用的最多的就是各個(gè)工廠模式了存淫,同時(shí)也趁著這個(gè)機(jī)會(huì)復(fù)習(xí)了一下工廠模式。這篇文章會(huì)詳細(xì)介紹一下各個(gè)工廠模式的優(yōu)缺點(diǎn)沼填,如果你能完全理解了以下三個(gè)實(shí)例那么工廠模式就不在話下了桅咆。由于業(yè)務(wù)代碼不能公開,文中用到的實(shí)例會(huì)使用其他例子代替坞笙。
我們知道Java里邊共有23種設(shè)計(jì)模式而工廠模式就有三種岩饼,它們分別是簡單工廠模式(并不在23中模式之中),工廠方法模式以及抽象工廠模式薛夜,其中我們通常所說的工廠模式指的是工廠方法模式籍茧,工廠方法模式是日常開發(fā)中使用頻率最高的一種設(shè)計(jì)模式,甚至在Android的源碼中也是隨處可見却邓。
下面按照學(xué)習(xí)的難易程度由淺入深的來說說這三種模式硕糊,每種模式都會(huì)先從定義,使用場景腊徙,實(shí)例三方面入手简十。很多小伙伴都說學(xué)習(xí)的時(shí)候感覺理解了,實(shí)例也能看得懂撬腾,可在實(shí)際開發(fā)中就不會(huì)運(yùn)用了螟蝙,這因?yàn)闆]有記住它的使用場景,各位小伙伴一定要結(jié)合實(shí)例記住使用場景民傻,這樣才能在開發(fā)中達(dá)到融匯貫通的效果胰默。這也說明了設(shè)計(jì)模式只是思想场斑,沒有固定的代碼!
首先來看最簡單的牵署。
簡單工廠模式
簡單工廠模式其實(shí)并不算是一種設(shè)計(jì)模式漏隐,更多的時(shí)候是一種編程習(xí)慣。
定義:
定義一個(gè)工廠類奴迅,根據(jù)傳入的參數(shù)不同返回不同的實(shí)例青责,被創(chuàng)建的實(shí)例具有共同的父類或接口。
適用場景:
其實(shí)由定義也大概能推測出其使用場景取具,首先由于只有一個(gè)工廠類脖隶,所以工廠類中創(chuàng)建的對(duì)象不能太多,否則工廠類的業(yè)務(wù)邏輯就太復(fù)雜了暇检,其次由于工廠類封裝了對(duì)象的創(chuàng)建過程产阱,所以客戶端應(yīng)該不關(guān)心對(duì)象的創(chuàng)建】槠停總結(jié)一下適用場景:
」沟拧(1)需要?jiǎng)?chuàng)建的對(duì)象較少。
≌ズ酢(2)客戶端不關(guān)心對(duì)象的創(chuàng)建過程怎燥。
以上就是簡單工廠模式簡單工廠模式的適用場景瘫筐,下面看一個(gè)具體的實(shí)例蜜暑。
實(shí)例:
創(chuàng)建一個(gè)可以繪制不同形狀的繪圖工具,可以繪制圓形策肝,正方形肛捍,三角形,每個(gè)圖形都會(huì)有一個(gè)draw()方法用于繪圖之众,不看代碼先考慮一下如何通過該模式設(shè)計(jì)完成此功能拙毫。
由題可知圓形,正方形棺禾,三角形都屬于一種圖形缀蹄,并且都具有draw方法,所以首先可以定義一個(gè)接口或者抽象類膘婶,作為這三個(gè)圖像的公共父類缺前,并在其中聲明一個(gè)公共的draw方法。
public interface Shape {
void draw();
}
這里定義成抽象類也是可以的悬襟,只不過接口是更高一級(jí)的抽象衅码,所以習(xí)慣定義成接口,而且接口支持多實(shí)現(xiàn)脊岳,方便以后擴(kuò)展逝段。
下面就是編寫具體的圖形垛玻,每種圖形都實(shí)現(xiàn)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");
}
}
下面是工廠類的具體實(shí)現(xiàn)
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;
}
}
在這個(gè)工廠類中通過傳入不同的type可以new不同的形狀,返回結(jié)果為Shape 類型奶躯,這個(gè)就是簡單工廠核心的地方了帚桩。
客戶端使用
畫圓形
Shape shape= ShapeFactory.getShape("circle");
shape.draw();
畫正方形
Shape shape= ShapeFactory.getShape("rect");
shape.draw();
畫三角形
Shape shape= ShapeFactory.getShape("triangle");
shape.draw();
只通過給ShapeFactory傳入不同的參數(shù)就實(shí)現(xiàn)了各種形狀的繪制。以上就是簡單工廠方式嘹黔,小伙伴們看明白了嗎朗儒?
工廠方法模式
工廠方法模式是簡單工廠的進(jìn)一步深化, 在工廠方法模式中参淹,我們不再提供一個(gè)統(tǒng)一的工廠類來創(chuàng)建所有的對(duì)象醉锄,而是針對(duì)不同的對(duì)象提供不同的工廠。也就是說每個(gè)對(duì)象都有一個(gè)與之對(duì)應(yīng)的工廠浙值。
定義:
定義一個(gè)用于創(chuàng)建對(duì)象的接口恳不,讓子類決定將哪一個(gè)類實(shí)例化。工廠方法模式讓一個(gè)類的實(shí)例化延遲到其子類开呐。
這次我們先用實(shí)例詳細(xì)解釋一下這個(gè)定義烟勋,最后在總結(jié)它的使用場景。
實(shí)例:
現(xiàn)在需要設(shè)計(jì)一個(gè)這樣的圖片加載類筐付,它具有多個(gè)圖片加載器卵惦,用來加載jpg,png瓦戚,gif格式的圖片沮尿,每個(gè)加載器都有一個(gè)read()方法,用于讀取圖片较解。下面我們完成這個(gè)圖片加載類畜疾。
首先完成圖片加載器的設(shè)計(jì),編寫一個(gè)加載器的公共接口印衔。
public interface Reader {
void read();
}
Reader 里面只有一個(gè)read()方法啡捶,然后完成各個(gè)圖片加載器的代碼。
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");
}
}
現(xiàn)在我們按照定義所說定義一個(gè)抽象的工廠接口ReaderFactory
public interface ReaderFactory {
Reader getReader();
}
里面有一個(gè)getReader()方法返回我們的Reader 類奸焙,接下來我們把上面定義好的每個(gè)圖片加載器都提供一個(gè)工廠類瞎暑,這些工廠類實(shí)現(xiàn)了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();
}
}
在每個(gè)工廠類中我們都通過復(fù)寫的getReader()方法返回各自的圖片加載器對(duì)象与帆。
客戶端使用
讀取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();
可以看到上面三段代碼了赌,分別讀取了不同格式的圖片,不同之處在于針對(duì)不同的圖片格式聲明了不同的工廠鲤桥,進(jìn)而創(chuàng)建了相應(yīng)的圖片加載器揍拆。
通過這個(gè)實(shí)例各位小伙伴是不是對(duì)工廠模式有了進(jìn)一步的理解呢,和簡單工廠對(duì)比一下茶凳,最根本的區(qū)別在于簡單工廠只有一個(gè)統(tǒng)一的工廠類嫂拴,而工廠方法是針對(duì)每個(gè)要?jiǎng)?chuàng)建的對(duì)象都會(huì)提供一個(gè)工廠類播揪,這些工廠類都實(shí)現(xiàn)了一個(gè)工廠基類(本例中的ReaderFactory )。下面總結(jié)一下工廠方法的適用場景筒狠。
適用場景:
(1)客戶端不需要知道它所創(chuàng)建的對(duì)象的類猪狈。例子中我們不知道每個(gè)圖片加載器具體叫什么名,只知道創(chuàng)建它的工廠名就完成了床架過程辩恼。
」兔怼(2)客戶端可以通過子類來指定創(chuàng)建對(duì)應(yīng)的對(duì)象。
以上場景使用于采用工廠方法模式灶伊。
抽象工廠模式
這個(gè)模式最不好理解疆前,而且在實(shí)際應(yīng)用中局限性也蠻大的,因?yàn)檫@個(gè)模式并不符合開閉原則聘萨。實(shí)際開發(fā)還需要做好權(quán)衡竹椒。
抽象工廠模式是工廠方法的進(jìn)一步深化,在這個(gè)模式中的工廠類不單單可以創(chuàng)建一個(gè)對(duì)象米辐,而是可以創(chuàng)建一組對(duì)象胸完。這是和工廠方法最大的不同點(diǎn)。
定義:
提供一個(gè)創(chuàng)建一系列相關(guān)或相互依賴對(duì)象的接口翘贮,而無須指定它們具體的類赊窥。( 在抽象工廠模式中,每一個(gè)具體工廠都提供了多個(gè)工廠方法用于產(chǎn)生多種不同類型的對(duì)象)
抽象工廠和工廠方法一樣可以劃分為4大部分:
AbstractFactory(抽象工廠)聲明了一組用于創(chuàng)建對(duì)象的方法狸页,注意是一組锨能。
ConcreteFactory(具體工廠):它實(shí)現(xiàn)了在抽象工廠中聲明的創(chuàng)建對(duì)象的方法,生成一組具體對(duì)象肴捉。
AbstractProduct(抽象產(chǎn)品):它為每種對(duì)象聲明接口腹侣,在其中聲明了對(duì)象所具有的業(yè)務(wù)方法叔收。
ConcreteProduct(具體產(chǎn)品):它定義具體工廠生產(chǎn)的具體對(duì)象齿穗。
下面還是先看一個(gè)具體實(shí)例。
實(shí)例:
現(xiàn)在需要做一款跨平臺(tái)的游戲饺律,需要兼容Android窃页,Ios,Wp三個(gè)移動(dòng)操作系統(tǒng)复濒,該游戲針對(duì)每個(gè)系統(tǒng)都設(shè)計(jì)了一套操作控制器(OperationController)和界面控制器(UIController)脖卖,下面通過抽閑工廠方式完成這款游戲的架構(gòu)設(shè)計(jì)。
由題可知巧颈,游戲里邊的各個(gè)平臺(tái)的UIController和OperationController應(yīng)該是我們最終生產(chǎn)的具體產(chǎn)品畦木。所以新建兩個(gè)抽象產(chǎn)品接口。
抽象操作控制器
public interface OperationController {
void control();
}
抽象界面控制器
public interface UIController {
void display();
}
然后完成各個(gè)系統(tǒng)平臺(tái)的具體操作控制器和界面控制器
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");
}
}
下面定義一個(gè)抽閑工廠砸泛,該工廠需要可以創(chuàng)建OperationController和UIController
public interface SystemFactory {
public OperationController createOperationController();
public UIController createInterfaceController();
}
在各平臺(tái)具體的工廠類中完成操作控制器和界面控制器的創(chuàng)建過程
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();
}
}
客戶端調(diào)用:
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();
針對(duì)不同平臺(tái)只通過創(chuàng)建不同的工廠對(duì)象就完成了操作和UI控制器的創(chuàng)建十籍。小伙伴們可以對(duì)比一下蛆封,如果這個(gè)游戲使用工廠方法模式搭建需要?jiǎng)?chuàng)建多少個(gè)工廠類呢?下面總結(jié)一下抽象工廠的適用場景勾栗。
適用場景:
(1)和工廠方法一樣客戶端不需要知道它所創(chuàng)建的對(duì)象的類惨篱。
(2)需要一組對(duì)象共同完成某種功能時(shí)。并且可能存在多組對(duì)象完成不同功能的情況围俘。
(3)系統(tǒng)結(jié)構(gòu)穩(wěn)定砸讳,不會(huì)頻繁的增加對(duì)象。(因?yàn)橐坏┰黾泳托枰薷脑写a界牡,不符合開閉原則)
以上就是三種工廠模式的總結(jié)簿寂,如有不對(duì)之處還希望各位留言指正,以免誤導(dǎo)他人宿亡。