工廠模式:優(yōu)雅地生成多種類型對象

工廠模式是一種非常常用的**創(chuàng)建型設計模式**隧熙,其提供了創(chuàng)建對象的最佳方式婉弹。在創(chuàng)建對象時睬魂,不會對客戶端暴露對象的創(chuàng)建邏輯,而是通過使用共同的接口來創(chuàng)建對象镀赌。通過使用工廠模式氯哮,在業(yè)務代碼中可以靈活的操控生成的實例對象。

工廠模式主要包含以下三種實現:**簡單工廠商佛、工廠方法及抽象工廠**喉钢。下面我們來逐一了解這三種工廠方法的實現與異同。

簡單工廠

工廠模式中良姆,最簡單易懂的就是簡單工廠方法肠虽。通俗點來說,簡單工廠的核心思想就是:“你告訴我你需要什么歇盼,我就為你生產什么”舔痕。這里舉一個游戲的簡單例子。一個游戲中角色分別有戰(zhàn)士豹缀、法師伯复、精靈。而我們需要設計一個相應的鐵匠鋪邢笙。根據不同的角色啸如,來鍛造不同的武器。(假設戰(zhàn)士是劍氮惯、法師是法杖叮雳,而精靈是弓)

那么編程思路其實很簡單,首先我們需要設計一個Player的基類對象妇汗,并定義一個基本的玩家類型Type字段帘不,用于判斷當前玩家是什么角色。然后分別定義出戰(zhàn)士杨箭、法師和精靈的對象寞焙。并對getType的方法進行覆蓋。簡單類圖如下:
具體類方法如下:
//玩家類
public class Player {
    String name;
    int type;

    public Player(String name) {
        this.name = name;
    }
}
public class Warrior extends Player {

    @Override
    public int getType() {
        return PlayerEnum.WARRIOR.getCode();
    }
}
在定義完玩家類以后,我們就可以設計咱們的鐵匠鋪類了捣郊。簡單來說辽狈,鐵匠鋪只需要調用getType方法判斷當前玩家的角色,并鍛造武器即可呛牲。
@Slf4j
public class BlackSmithShopSimpleFactory {

    public static Weapon createWeapon(Player player) {
        //簡單工廠中設計判斷即可
        Weapon weapon = null;
        if (player.getType() == WARRIOR.getCode()) {
            weapon = new Sword();
        } else if (player.getType() == ELF.getCode()) {
            weapon = new Bow();
        } else if (player.getType() == MAGE.getCode()) {
            weapon = new Staff();
        }
        return weapon;
    }

    public static void main(String[] args) {
        Player player1 = new Warrior();
        Weapon weapon1 = createWeapon(player1);
        System.out.println("player1從鐵匠鋪獲取到的武器是:"+weapon1.getDesc());

        Player player2 = new Mage();
        Weapon weapon2 = createWeapon(player2);
        System.out.println("player2從鐵匠鋪獲取到的武器是:"+ weapon2.getDesc());

        Player player3 = new Elf();
        Weapon weapon3 = createWeapon(player3);
        System.out.println("player3從鐵匠鋪獲取到的武器是:"+ weapon3.getDesc());
    }
}
最終的輸出結果如下:
可以看到刮萌,簡單工廠在對應不同玩家的時候都能生成出相應的對象,實現了靈活的機制娘扩。但是需要注意的是着茸,簡單工廠其實是違背了**開閉原則**的。例如我們可能需要新增玩家角色 - 刺客畜侦,其使用的武器是飛鏢元扔,那么此時我們就需要修改鐵匠鋪的代碼,新增上飛鏢這種類型旋膳。

簡單工廠代碼雖然違反了開閉原則且可能需要頻繁增加生成代碼澎语,但是勝在簡單易實現,且可讀性較好验懊。大多數時候都能勝任問題擅羞。

工廠方法

工廠方法模式是對簡單工廠模式的進一步深化,其不像簡單工廠模式通過一個工廠來完成所有對象的創(chuàng)建义图,而是**通過不同的工廠來創(chuàng)建不同的對象**减俏,每個對象有對應的工廠創(chuàng)建。

依舊是以上面的游戲為例子碱工,假設游戲當前不再針對職業(yè)進行武器的限制了娃承。玩家可以任意地選擇合適的武器,那么此時就可以采用工廠方法進行改造怕篷。
首先历筝,定義一個抽象類或接口,其中規(guī)定咱們的創(chuàng)建武器的方法廊谓。然后梳猪,分別定義生產法杖、生產弓和生產劍的鐵匠鋪蒸痹。并實現對應的方法春弥。緊接著,根據玩家的具體需要去生成相應的武器即可叠荠。選擇工廠并生產的代碼如下: 
public class BlackSmithShopFactoryPattern {

    public static void main(String[] args) {
        Player player = new Player();

        //生產劍的鐵匠鋪
        WeaponShop swordShop = new SwordShop();
        Weapon weapon = swordShop.createWeapon();
        System.out.println("玩家選擇的武器為:"+weapon.getDesc());

        //生產弓的鐵匠鋪
        WeaponShop staffShop = new StaffShop();
        Weapon weapon1 = staffShop.createWeapon();
        System.out.println("玩家選擇的武器為:"+weapon1.getDesc());

        //生產法杖的鐵匠鋪
        BowShop bowShop = new BowShop();
        Weapon weapon2 = bowShop.createWeapon();
        System.out.println("玩家選擇的武器為:"+weapon2.getDesc());
    }
}
最終的結果如下:
工廠方法的優(yōu)勢在于擴展性相對比較好匿沛,當需要新增工廠的時候,只需要進行相應的拓展即可實現榛鼎。例如我們如果要新增武器俺祠,只需要寫一個類再實現相應的生產武器的方法即可公给。

但是借帘,問題在于過多的類很可能會影響整個系統(tǒng)的可讀性蜘渣,增大系統(tǒng)的復雜度。

抽象工廠

抽象工廠肺然,其實是工廠方法的拓展蔫缸。上述無論是工廠方法還是簡單工廠,都是針對一個對象進行設計和封裝际起,但是實際情況中往往會存在一些連帶的情況拾碌。還是以上述游戲的情況為例子。假設當前我們要打造的不再是單一的武器街望,而是需要打造對應的武器和盔甲校翔。同時,武器和盔甲必須成套打造才有相應的屬性加成灾前。那么這個時候防症,工廠方法和簡單工廠就比較難滿足我們的需求了。

針對這個情況哎甲,我們可以設計相應的抽象工廠解決蔫敲。這里我們首先假定套裝有兩套,黑龍?zhí)籽b和紅龍?zhí)籽b炭玫。

首先咱們先設計一個抽象的套裝工廠奈嘿,其兩個方法分別是生產武器和盔甲。
public abstract class SuitShop {
    public abstract Weapon createWeapon();

    public abstract Armor createArmor();
}
隨后根據職業(yè)和套裝指定相應的工廠實現子類吞加。(這里僅僅實現了戰(zhàn)士的工廠實現子類裙犹,其余角色的子類實現類似)
public class RedDragonWarriorSuitShop extends SuitShop{
    @Override
    public Weapon createWeapon() {
        return new RedDragonSword();
    }

    @Override
    public Armor createArmor() {
        return new RedDragonPlate();
    }
}
public class BlackDragonWarriorSuitShop extends SuitShop{

    @Override
    public Weapon createWeapon() {
        return new BlackDragonSword();
    }

    @Override
    public Armor createArmor() {
        return new BlackDragonPlate();
    }
}
除了工廠,我們還要定義對應的黑龍?zhí)籽b和紅龍?zhí)籽b對應的武器和盔甲的子類衔憨。
public class BlackDragonSword extends Sword{
    @Override
    public String getDesc() {
        return "黑龍劍";
    }
}
public class BlackDragonPlate extends Plate{
    @Override
    public String getDesc() {
        return "黑龍板甲";
    }
}
public class RedDragonPlate extends Plate{
    @Override
    public String getDesc() {
        return "紅龍板甲";
    }
}
public class RedDragonSword extends Sword{
    @Override
    public String getDesc() {
        return "紅龍劍";
    }
}
最終定義的整體類圖如下所示:
public class BlackSmithShopAbstractFactory {

    public static void main(String[] args) {
        SuitShop suitShop = new BlackDragonWarriorSuitShop();
        Weapon weapon = suitShop.createWeapon();
        Armor armor = suitShop.createArmor();

        System.out.println("玩家打造的套裝是:"+weapon.getDesc()+"和"+armor.getDesc());

        SuitShop redDragonWarriorSuitShop = new RedDragonWarriorSuitShop();
        Weapon weapon1 = redDragonWarriorSuitShop.createWeapon();
        Armor armor1 = redDragonWarriorSuitShop.createArmor();
        System.out.println("玩家打造的套裝是:"+weapon1.getDesc()+"和"+armor1.getDesc());
    }
}
在main方法中定義相應的邏輯叶圃,然后執(zhí)行得到如下結果。
總的來說巫财,抽象工廠主要是針對多個類型對象的時候使用的方法盗似。但其缺點也很明顯,首先是需要增加較多的類來實現相應的邏輯平项。其次是該方式也不符合開閉原則赫舒,如果需要修改的時候,是需要對工廠和對象都進行相應的代碼修改的闽瓢。例如如果需要再增加一個頭盔接癌,就可能影響到各個套裝都需要增加對頭盔的鍛造邏輯的實現。

總結

本文介紹了工廠模式對應的三種不同實現方法扣讼,包括**簡單工廠**缺猛、**工廠方法**以及**抽象工廠**。三種實現方法也各有優(yōu)劣。
  1. 簡單工廠荔燎,邏輯簡單耻姥,代碼邏輯易懂,但是不符合開閉原則有咨,增加工廠需要改動相應的判斷邏輯琐簇。
  2. 工廠方法,對于簡單工廠做了進一步的抽象座享,新增工廠只需要新增加相應的工廠類即可婉商,不涉及到工廠判斷的邏輯。但是會存在多個工廠的情況下渣叛,類的數目增多的情況丈秩。
  3. 抽象工廠,是對于工廠方法的進一步抽象淳衙,其支持同時生生成多個對象蘑秽。通過新增加工廠類可以新增加需要生成的組合對象。但是問題在于其也違背了開閉原則滤祖,當需要生成的對象數量增多時筷狼,相應的邏輯需要進行修改和增加。
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末匠童,一起剝皮案震驚了整個濱河市埂材,隨后出現的幾起案子,更是在濱河造成了極大的恐慌汤求,老刑警劉巖俏险,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異扬绪,居然都是意外死亡竖独,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進店門挤牛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來莹痢,“玉大人,你說我怎么就攤上這事墓赴【荷牛” “怎么了?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵诫硕,是天一觀的道長坦辟。 經常有香客問我,道長章办,這世上最難降的妖魔是什么锉走? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任滨彻,我火速辦了婚禮,結果婚禮上挪蹭,老公的妹妹穿的比我還像新娘亭饵。我一直安慰自己,他們只是感情好嚣潜,可當我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布冬骚。 她就那樣靜靜地躺著,像睡著了一般懂算。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上庇麦,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天计技,我揣著相機與錄音,去河邊找鬼山橄。 笑死垮媒,一個胖子當著我的面吹牛,可吹牛的內容都是我干的航棱。 我是一名探鬼主播睡雇,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼饮醇!你這毒婦竟也來了它抱?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤朴艰,失蹤者是張志新(化名)和其女友劉穎观蓄,沒想到半個月后,有當地人在樹林里發(fā)現了一具尸體祠墅,經...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡侮穿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現自己被綠了毁嗦。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片亲茅。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖狗准,靈堂內的尸體忽然破棺而出克锣,到底是詐尸還是另有隱情,我是刑警寧澤驶俊,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布娶耍,位于F島的核電站,受9級特大地震影響饼酿,放射性物質發(fā)生泄漏榕酒。R本人自食惡果不足惜胚膊,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望想鹰。 院中可真熱鬧紊婉,春花似錦、人聲如沸辑舷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽何缓。三九已至肢础,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間碌廓,已是汗流浹背传轰。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留谷婆,地道東北人慨蛙。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像纪挎,于是被迫代替她去往敵國和親期贫。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內容