工廠模式: 深入理解工廠模式——由對象工廠生成對象

目錄:

一 工廠模式介紹

1.1 工廠模式的定義

1.2 工廠模式的分類:

1.3 在開源框架中的使用

1.4 為什么要用工廠模式

二 簡單工廠模式

2.1 介紹

2.2 適用場景

2.3 簡單工廠模式角色分配:

2.4 簡單工廠實例

2.5 使用反射機制改善簡單工廠

3 工廠方法模式

3.1 介紹

3.2 適用場景

3.3 工廠方法模式角色分配:

3.4 工廠方法模式實例

4 抽象工廠模式

4.1 介紹

4.2 適用場景

4.3 抽象工廠方法模式角色分配:

4.4 抽象工廠的工廠和工廠方法中的工廠有什么區(qū)別呢易阳?

4.5 抽象工廠模式實例

一 工廠模式介紹

1.1 工廠模式的定義

先來看一下GOF為工廠模式的定義:

“Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.”(在基類中定義創(chuàng)建對象的一個接口,讓子類決定實例化哪個類透典。工廠方法讓一個類的實例化延遲到子類中進行芭商。)

1.2 工廠模式的分類:

(1)簡單工廠(Simple Factory)模式怜庸,又稱靜態(tài)工廠方法模式(Static Factory Method Pattern)。

(2)工廠方法(Factory Method)模式,又稱多態(tài)性工廠(Polymorphic Factory)模式或虛擬構(gòu)造子(Virtual Constructor)模式狂鞋;

(3)抽象工廠(Abstract Factory)模式,又稱工具箱(Kit 或Toolkit)模式潜的。

1.3 在開源框架中的使用

舉兩個比較常見的例子(我暫時可以準確想到的骚揍,當然還有很多很多):

(1)Spring中通過getBean(“xxx”)獲取Bean;

(2) Java消息服務(wù)JMS中(下面以消息隊列ActiveMQ為例子)

關(guān)于消息隊列ActiveMQ的使用可以查看:消息隊列ActiveMQ的使用詳解

// 1啰挪、創(chuàng)建一個連接工廠對象信不,需要指定服務(wù)的ip及端口。
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://192.168.25.155:61616");
// 2亡呵、使用工廠對象創(chuàng)建一個Connection對象抽活。

1.4 為什么要用工廠模式

(1) 解耦 :把對象的創(chuàng)建和使用的過程分開

(2)降低代碼重復(fù): 如果創(chuàng)建某個對象的過程都很復(fù)雜,需要一定的代碼量锰什,而且很多地方都要用到下硕,那么就會有很多的重復(fù)代碼。

(3) 降低維護成本 :由于創(chuàng)建過程都由工廠統(tǒng)一管理汁胆,所以發(fā)生業(yè)務(wù)邏輯變化梭姓,不需要找到所有需要創(chuàng)建對象B的地方去逐個修正,只需要在工廠里修改即可嫩码,降低維護成本誉尖。

關(guān)于工廠模式的作用,Mark一篇文章:https://blog.csdn.net/lovelion/article/details/7523392

二 簡單工廠模式

2.1 介紹

嚴格的說谢谦,簡單工廠模式并不是23種常用的設(shè)計模式之一释牺,它只算工廠模式的一個特殊實現(xiàn)萝衩。簡單工廠模式在實際中的應(yīng)用相對于其他2個工廠模式用的還是相對少得多,因為它只適應(yīng)很多簡單的情況没咙。

最重要的是它違背了我們在概述中說的 開放-封閉原則 (雖然可以通過反射的機制來避免猩谊,后面我們會介紹到) 。因為每次你要新添加一個功能祭刚,都需要在生switch-case 語句(或者if-else 語句)中去修改代碼牌捷,添加分支條件。

2.2 適用場景

(1)需要創(chuàng)建的對象較少涡驮。

(2)客戶端不關(guān)心對象的創(chuàng)建過程暗甥。

2.3 簡單工廠模式角色分配:

工廠(Factory)角色 :簡單工廠模式的核心,它負責實現(xiàn)創(chuàng)建所有實例的內(nèi)部邏輯捉捅。工廠類可以被外界直接調(diào)用撤防,創(chuàng)建所需的產(chǎn)品對象。
抽象產(chǎn)品(Product)角色 :簡單工廠模式所創(chuàng)建的所有對象的父類,它負責描述所有實例所共有的公共接口。
具體產(chǎn)品(Concrete Product)角色:簡單工廠模式的創(chuàng)建目標手负,所有創(chuàng)建的對象都是充當這個角色的某個具體類的實例。

2.4 簡單工廠實例

創(chuàng)建一個可以繪制不同形狀的繪圖工具漾肮,可以繪制圓形,正方形茎毁,三角形克懊,每個圖形都會有一個draw()方法用于繪圖.

(1)創(chuàng)建Shape接口

public interface Shape {
void draw();
}

(2)創(chuàng)建實現(xiàn)該接口的具體圖形類

圓形

public class Circle implements Shape {
public Circle() {
System.out.println("Circle");
}
@Override
public void draw() {
System.out.println("Draw Circle");
}
}

長方形

public class Rectangle implements Shape {
public Rectangle() {
    System.out.println("Rectangle");
}
@Override
public void draw() {
    System.out.println("Draw Rectangle");
}
}

正方形

public class Square implements Shape {
public Square() {
System.out.println("Square");
}

@Override
public void draw() {
System.out.println("Draw Square");
}
}

(3)創(chuàng)建工廠類:

public class ShapeFactory {

// 使用 getShape 方法獲取形狀類型的對象
public static Shape getShape(String shapeType) {
if (shapeType == null) {
return null;
}
if (shapeType.equalsIgnoreCase("CIRCLE")) {
return new Circle();
} else if (shapeType.equalsIgnoreCase("RECTANGLE")) {
return new Rectangle();
} else if (shapeType.equalsIgnoreCase("SQUARE")) {
return new Square();
}
return null;
}
}

(4)測試方法:

public class Test {

public static void main(String[] args) {

// 獲取 Circle 的對象,并調(diào)用它的 draw 方法
Shape circle = ShapeFactory.getShape("CIRCLE");
circle.draw();

// 獲取 Rectangle 的對象七蜘,并調(diào)用它的 draw 方法
Shape rectangle = ShapeFactory.getShape("RECTANGLE");
rectangle.draw();

// 獲取 Square 的對象谭溉,并調(diào)用它的 draw 方法
Shape square = ShapeFactory.getShape("SQUARE");
square.draw();
}
}

輸出結(jié)果:

Circle
Draw Circle
Rectangle
Draw Rectangle
Square
Draw Square

這樣的實現(xiàn)有個問題,如果我們新增產(chǎn)品類的話崔梗,就需要修改工廠類中的getShape()方法夜只,這很明顯不符合 開放-封閉原則 。

2.5 使用反射機制改善簡單工廠

將工廠類改為下面的形式:

package factory_pattern;

/**
 * 利用反射解決簡單工廠每次增加新了產(chǎn)品類都要修改產(chǎn)品工廠的弊端
 * 
 * @author Administrator
 *
 */
public class ShapeFactory2 {
public static Object getClass(Class<? extends Shape> clazz) {
Object obj = null;

try {
obj = Class.forName(clazz.getName()).newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}

return obj;
}
}

測試方法:

package factory_pattern;

public class Test2 {
public static void main(String[] args) {

Circle circle = (Circle) ShapeFactory2.getClass(factory_pattern.Circle.class);
circle.draw();

Rectangle rectangle = (Rectangle) ShapeFactory2.getClass(factory_pattern.Rectangle.class);
rectangle.draw();

Square square = (Square) ShapeFactory2.getClass(factory_pattern.Square.class);
square.draw();
}

}

這種方式的雖然符合了 開放-關(guān)閉原則 蒜魄,但是每一次傳入的都是產(chǎn)品類的全部路徑扔亥,這樣比較麻煩。如果需要改善的話可以通過 反射+配置文件 的形式來改善谈为,這種方式使用的也是比較多的旅挤。

3 工廠方法模式

3.1 介紹

工廠方法模式應(yīng)該是在工廠模式家族中是用的最多模式,一般項目中存在最多的就是這個模式伞鲫。

工廠方法模式是簡單工廠的僅一步深化粘茄, 在工廠方法模式中,我們不再提供一個統(tǒng)一的工廠類來創(chuàng)建所有的對象,而是針對不同的對象提供不同的工廠柒瓣。也就是說 每個對象都有一個與之對應(yīng)的工廠 儒搭。

3.2 適用場景

一個類不知道它所需要的對象的類:在工廠方法模式中,客戶端不需要知道具體產(chǎn)品類的類名芙贫,只需要知道所對應(yīng)的工廠即可搂鲫,具體的產(chǎn)品對象由具體工廠類創(chuàng)建;客戶端需要知道創(chuàng)建具體產(chǎn)品的工廠類磺平。
一個類通過其子類來指定創(chuàng)建哪個對象:在工廠方法模式中魂仍,對于抽象工廠類只需要提供一個創(chuàng)建產(chǎn)品的接口,而由其子類來確定具體要創(chuàng)建的對象拣挪,利用面向?qū)ο蟮亩鄳B(tài)性和里氏
將創(chuàng)建對象的任務(wù)委托給多個工廠子類中的某一個擦酌,客戶端在使用時可以無需關(guān)心是哪一個工廠子類創(chuàng)建產(chǎn)品子類,需要時再動態(tài)指定菠劝,可將具體工廠類的類名存儲在配置文件或數(shù)據(jù)庫中赊舶。

3.3 工廠方法模式角色分配:

抽象工廠(Abstract Factory)角色:是工廠方法模式的核心,與應(yīng)用程序無關(guān)赶诊。任何在模式中創(chuàng)建的對象的工廠類必須實現(xiàn)這個接口锯岖。
具體工廠(Concrete Factory)角色 :這是實現(xiàn)抽象工廠接口的具體工廠類,包含與應(yīng)用程序密切相關(guān)的邏輯甫何,并且受到應(yīng)用程序調(diào)用以創(chuàng)建某一種產(chǎn)品對象。
抽象產(chǎn)品(AbstractProduct)角色 :工廠方法模式所創(chuàng)建的對象的超類型遇伞,也就是產(chǎn)品對象的共同父類或共同擁有的接口辙喂。
具體產(chǎn)品(Concrete Product)角色 :這個角色實現(xiàn)了抽象產(chǎn)品角色所定義的接口。某具體產(chǎn)品有專門的具體工廠創(chuàng)建鸠珠,它們之間往往一一對應(yīng)

3.4 工廠方法模式實例

上面簡單工廠例子中的圖形接口以及相關(guān)圖像實現(xiàn)類不變巍耗。我們只需要增加一個工廠接口以及實現(xiàn)這個接口的工廠類即可。

(1)增加一個工廠接口:

public interface Factory {
    public Shape getShape();
}

(2)增加相關(guān)工廠類:

圓形工廠類

public class CircleFactory implements Factory {

@Override
public Shape getShape() {
// TODO Auto-generated method stub
return new Circle();
}

}

長方形工廠類

public class RectangleFactory implements Factory{

@Override
public Shape getShape() {
// TODO Auto-generated method stub
return new Rectangle();
}

}

圓形工廠類

public class SquareFactory implements Factory{

@Override
public Shape getShape() {
// TODO Auto-generated method stub
return new Square();
}

}

(3)測試:

public class Test {

public static void main(String[] args) {
Factory circlefactory = new CircleFactory();
Shape circle = circlefactory.getShape();
circle.draw();
}

}

輸出結(jié)果:

Circle
Draw Circle

4 抽象工廠模式

4.1 介紹

在工廠方法模式中渐排,其實我們有一個潛在意識的意識炬太。那就是我們生產(chǎn)的都是同一類產(chǎn)品。抽象工廠模式是工廠方法的僅一步深化驯耻,在這個模式中的工廠類不單單可以創(chuàng)建一種產(chǎn)品亲族,而是可以創(chuàng)建一組產(chǎn)品。

抽象工廠應(yīng)該是比較最難理解的一個工廠模式了可缚。

4.2 適用場景

和工廠方法一樣客戶端不需要知道它所創(chuàng)建的對象的類霎迫。
需要一組對象共同完成某種功能時,并且可能存在多組對象完成不同功能的情況帘靡。(同屬于同一個產(chǎn)品族的產(chǎn)品)
系統(tǒng)結(jié)構(gòu)穩(wěn)定知给,不會頻繁的增加對象。(因為一旦增加就需要修改原有代碼,不符合開閉原則)

4.3 抽象工廠方法模式角色分配:

抽象工廠(AbstractFactory)角色 :是工廠方法模式的核心涩赢,與應(yīng)用程序無關(guān)戈次。任何在模式中創(chuàng)建的對象的工廠類必須實現(xiàn)這個接口。
具體工廠類(ConreteFactory)角色 :這是實現(xiàn)抽象工廠接口的具體工廠類筒扒,包含與應(yīng)用程序密切相關(guān)的邏輯怯邪,并且受到應(yīng)用程序調(diào)用以創(chuàng)建某一種產(chǎn)品對象。
抽象產(chǎn)品(Abstract Product)角色 :工廠方法模式所創(chuàng)建的對象的超類型霎肯,也就是產(chǎn)品對象的共同父類或共同擁有的接口擎颖。
具體產(chǎn)品(Concrete Product)角色 :抽象工廠模式所創(chuàng)建的任何產(chǎn)品對象都是某一個具體產(chǎn)品類的實例。在抽象工廠中創(chuàng)建的產(chǎn)品屬于同一產(chǎn)品族观游,這不同于工廠模式中的工廠只創(chuàng)建單一產(chǎn)品搂捧,我后面也會詳解介紹到。
懂缕。

4.4 抽象工廠的工廠和工廠方法中的工廠有什么區(qū)別呢允跑?

抽象工廠是生產(chǎn)一整套有產(chǎn)品的(至少要生產(chǎn)兩個產(chǎn)品),這些產(chǎn)品必須相互是有關(guān)系或有依賴的搪柑,而工廠方法中的工廠是生產(chǎn)單一產(chǎn)品的工廠聋丝。

下面就是抽象工廠圖示:

4.5 抽象工廠模式實例

不知道大家玩過穿越火線或者吃雞這類游戲了嗎,游戲中存在各種槍工碾。我們假設(shè)現(xiàn)在存在AK弱睦、M4A1兩類槍,每一種槍對應(yīng)一種子彈渊额。我們現(xiàn)在這樣考慮生產(chǎn)AK的工廠可以順便生產(chǎn)AK使用的子彈况木,生產(chǎn)M4A1的工廠可以順便生產(chǎn)M4A1使用的子彈。(AK工廠生產(chǎn)AK系列產(chǎn)品包括子彈啊旬迹,AK槍的類型啊這些火惊,M4A1工廠同理)

(1)創(chuàng)建相關(guān)接口:

public interface Gun {
    public void shooting();
}

子彈

public interface Bullet {
    public void load();
}

(2)創(chuàng)建接口對應(yīng)實現(xiàn)類:

AK類

public class AK implements Gun{

@Override
public void shooting() {
System.out.println("shooting with AK");

}

}

M4A1類

public class M4A1 implements Gun {

@Override
public void shooting() {
System.out.println("shooting with M4A1");

}

}

AK子彈類

public class AK_Bullet implements Bullet {

@Override
public void load() {
System.out.println("Load bullets with AK");
}

}

M4A1子彈類

public class M4A1
_Bullet implements Bullet {

@Override
public void load() {
System.out.println("Load bullets with M4A1");
}

}

(3)創(chuàng)建工廠接口

public interface Factory {
    public Gun produceGun();
    public Bullet produceBullet();
}

(4)創(chuàng)建具體工廠

生產(chǎn)AK和AK子彈的工廠

public class AK_Factory implements Factory{

@Override
public Gun produceGun() {
return new AK();
}

@Override
public Bullet produceBullet() {
return new AK_Bullet();
}

}

生產(chǎn)M4A1和M4A1子彈的工廠

public class M4A1_Factory implements Factory{

@Override
public Gun produceGun() {
return new M4A1();
}

@Override
public Bullet produceBullet() {
return new M4A1_Bullet();
}

}

(5)測試

public class Test {

public static void main(String[] args) {  

 Factory factory;
 Gun gun;
 Bullet bullet;

 factory =new AK_Factory();
 bullet=factory.produceBullet();
 bullet.load();
 gun=factory.produceGun();
 gun.shooting(); 

}

}

輸出結(jié)果:

Load bullets with AK
shooting with AK

作者:SnailClimb在CSDN
來源:CSDN
原文:https://blog.csdn.net/qq_34337272/article/details/80472071

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市奔垦,隨后出現(xiàn)的幾起案子屹耐,更是在濱河造成了極大的恐慌,老刑警劉巖椿猎,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件惶岭,死亡現(xiàn)場離奇詭異,居然都是意外死亡鸵贬,警方通過查閱死者的電腦和手機俗他,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來阔逼,“玉大人兆衅,你說我怎么就攤上這事。” “怎么了羡亩?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵摩疑,是天一觀的道長。 經(jīng)常有香客問我畏铆,道長雷袋,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任辞居,我火速辦了婚禮楷怒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘瓦灶。我一直安慰自己鸠删,他們只是感情好,可當我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布贼陶。 她就那樣靜靜地躺著刃泡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪碉怔。 梳的紋絲不亂的頭發(fā)上烘贴,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天,我揣著相機與錄音撮胧,去河邊找鬼桨踪。 笑死,一個胖子當著我的面吹牛芹啥,可吹牛的內(nèi)容都是我干的馒闷。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼叁征,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了逛薇?” 一聲冷哼從身側(cè)響起捺疼,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎永罚,沒想到半個月后啤呼,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡呢袱,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年官扣,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片羞福。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡惕蹄,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情卖陵,我是刑警寧澤遭顶,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站泪蔫,受9級特大地震影響棒旗,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜撩荣,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一铣揉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧餐曹,春花似錦逛拱、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至卿吐,卻和暖如春旁舰,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背嗡官。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工箭窜, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人衍腥。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓磺樱,卻偏偏與公主長得像,于是被迫代替她去往敵國和親婆咸。 傳聞我的和親對象是個殘疾皇子竹捉,可洞房花燭夜當晚...
    茶點故事閱讀 43,446評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 設(shè)計模式概述 在學(xué)習(xí)面向?qū)ο笃叽笤O(shè)計原則時需要注意以下幾點:a) 高內(nèi)聚、低耦合和單一職能的“沖突”實際上尚骄,這兩者...
    彥幀閱讀 3,735評論 0 14
  • 字節(jié)跳動飛書內(nèi)推块差!北京、杭州倔丈、武漢憨闰、廣州、深圳需五、上海鹉动,六大城市等你來投。感興趣的朋友可以私我咨詢&內(nèi)推宏邮,也可以通過...
    盧卡斯嗶嗶嗶閱讀 606評論 0 3
  • 工廠模式是我們最常用的實例化對象模式了泽示,是用工廠方法代替new操作的一種模式缸血。通常我們所說的工廠模式是指工廠方法模...
    zfylin閱讀 1,310評論 0 7
  • 鳳釵頭·世情薄 作者【唐婉 】【朝代】 宋朝 世情薄,人情惡边琉,雨送黃昏花易落属百。曉風(fēng)乾,淚痕殘变姨,欲箋心事族扰,獨語斜欄。...
    陸陸續(xù)續(xù)說閱讀 314評論 0 0
  • 一.用CSS3的好處 1.使用簡單定欧,易于學(xué)習(xí) 2.性能相對優(yōu)化 二.學(xué)習(xí)前需要了解的知識 html5基本語法 cs...
    緣叔叔閱讀 9,670評論 2 10