工廠模式是一種非常常用的**創(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)劣。
-
簡單工廠荔燎,邏輯簡單耻姥,代碼邏輯易懂,但是不符合開閉原則有咨,增加工廠需要改動相應的判斷邏輯琐簇。
-
工廠方法,對于簡單工廠做了進一步的抽象座享,新增工廠只需要新增加相應的工廠類即可婉商,不涉及到工廠判斷的邏輯。但是會存在多個工廠的情況下渣叛,類的數目增多的情況丈秩。
-
抽象工廠,是對于工廠方法的進一步抽象淳衙,其支持同時生生成多個對象蘑秽。通過新增加工廠類可以新增加需要生成的組合對象。但是問題在于其也違背了開閉原則滤祖,當需要生成的對象數量增多時筷狼,相應的邏輯需要進行修改和增加。