工廠模式是一種非常常用的**創(chuàng)建型設(shè)計(jì)模式**,其提供了創(chuàng)建對(duì)象的最佳方式。在創(chuàng)建對(duì)象時(shí),不會(huì)對(duì)客戶端暴露對(duì)象的創(chuàng)建邏輯,而是通過(guò)使用共同的接口來(lái)創(chuàng)建對(duì)象。通過(guò)使用工廠模式,在業(yè)務(wù)代碼中可以靈活的操控生成的實(shí)例對(duì)象。
工廠模式主要包含以下三種實(shí)現(xiàn):**簡(jiǎn)單工廠、工廠方法及抽象工廠**。下面我們來(lái)逐一了解這三種工廠方法的實(shí)現(xiàn)與異同。
簡(jiǎn)單工廠
工廠模式中,最簡(jiǎn)單易懂的就是簡(jiǎn)單工廠方法。通俗點(diǎn)來(lái)說(shuō),簡(jiǎn)單工廠的核心思想就是:“你告訴我你需要什么,我就為你生產(chǎn)什么”。這里舉一個(gè)游戲的簡(jiǎn)單例子。一個(gè)游戲中角色分別有戰(zhàn)士、法師、精靈。而我們需要設(shè)計(jì)一個(gè)相應(yīng)的鐵匠鋪。根據(jù)不同的角色,來(lái)鍛造不同的武器。(假設(shè)戰(zhàn)士是劍、法師是法杖,而精靈是弓)
那么編程思路其實(shí)很簡(jiǎn)單,首先我們需要設(shè)計(jì)一個(gè)Player的基類對(duì)象,并定義一個(gè)基本的玩家類型Type字段,用于判斷當(dāng)前玩家是什么角色。然后分別定義出戰(zhàn)士、法師和精靈的對(duì)象。并對(duì)getType的方法進(jìn)行覆蓋。簡(jiǎn)單類圖如下:
具體類方法如下:
//玩家類
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();
}
}
在定義完玩家類以后,我們就可以設(shè)計(jì)咱們的鐵匠鋪類了。簡(jiǎn)單來(lái)說(shuō),鐵匠鋪只需要調(diào)用getType方法判斷當(dāng)前玩家的角色,并鍛造武器即可。
@Slf4j
public class BlackSmithShopSimpleFactory {
public static Weapon createWeapon(Player player) {
//簡(jiǎn)單工廠中設(shè)計(jì)判斷即可
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());
}
}
最終的輸出結(jié)果如下:
可以看到,簡(jiǎn)單工廠在對(duì)應(yīng)不同玩家的時(shí)候都能生成出相應(yīng)的對(duì)象,實(shí)現(xiàn)了靈活的機(jī)制。但是需要注意的是,簡(jiǎn)單工廠其實(shí)是違背了**開(kāi)閉原則**的。例如我們可能需要新增玩家角色 - 刺客,其使用的武器是飛鏢,那么此時(shí)我們就需要修改鐵匠鋪的代碼,新增上飛鏢這種類型。
簡(jiǎn)單工廠代碼雖然違反了開(kāi)閉原則且可能需要頻繁增加生成代碼,但是勝在簡(jiǎn)單易實(shí)現(xiàn),且可讀性較好。大多數(shù)時(shí)候都能勝任問(wèn)題。
工廠方法
工廠方法模式是對(duì)簡(jiǎn)單工廠模式的進(jìn)一步深化,其不像簡(jiǎn)單工廠模式通過(guò)一個(gè)工廠來(lái)完成所有對(duì)象的創(chuàng)建,而是**通過(guò)不同的工廠來(lái)創(chuàng)建不同的對(duì)象**,每個(gè)對(duì)象有對(duì)應(yīng)的工廠創(chuàng)建。
依舊是以上面的游戲?yàn)槔?,假設(shè)游戲當(dāng)前不再針對(duì)職業(yè)進(jìn)行武器的限制了。玩家可以任意地選擇合適的武器,那么此時(shí)就可以采用工廠方法進(jìn)行改造。
首先,定義一個(gè)抽象類或接口,其中規(guī)定咱們的創(chuàng)建武器的方法。然后,分別定義生產(chǎn)法杖、生產(chǎn)弓和生產(chǎn)劍的鐵匠鋪。并實(shí)現(xiàn)對(duì)應(yīng)的方法。緊接著,根據(jù)玩家的具體需要去生成相應(yīng)的武器即可。選擇工廠并生產(chǎn)的代碼如下:
public class BlackSmithShopFactoryPattern {
public static void main(String[] args) {
Player player = new Player();
//生產(chǎn)劍的鐵匠鋪
WeaponShop swordShop = new SwordShop();
Weapon weapon = swordShop.createWeapon();
System.out.println("玩家選擇的武器為:"+weapon.getDesc());
//生產(chǎn)弓的鐵匠鋪
WeaponShop staffShop = new StaffShop();
Weapon weapon1 = staffShop.createWeapon();
System.out.println("玩家選擇的武器為:"+weapon1.getDesc());
//生產(chǎn)法杖的鐵匠鋪
BowShop bowShop = new BowShop();
Weapon weapon2 = bowShop.createWeapon();
System.out.println("玩家選擇的武器為:"+weapon2.getDesc());
}
}
最終的結(jié)果如下:
工廠方法的優(yōu)勢(shì)在于擴(kuò)展性相對(duì)比較好,當(dāng)需要新增工廠的時(shí)候,只需要進(jìn)行相應(yīng)的拓展即可實(shí)現(xiàn)。例如我們?nèi)绻略鑫淦?,只需要?xiě)一個(gè)類再實(shí)現(xiàn)相應(yīng)的生產(chǎn)武器的方法即可。
但是,問(wèn)題在于過(guò)多的類很可能會(huì)影響整個(gè)系統(tǒng)的可讀性,增大系統(tǒng)的復(fù)雜度。
抽象工廠
抽象工廠,其實(shí)是工廠方法的拓展。上述無(wú)論是工廠方法還是簡(jiǎn)單工廠,都是針對(duì)一個(gè)對(duì)象進(jìn)行設(shè)計(jì)和封裝,但是實(shí)際情況中往往會(huì)存在一些連帶的情況。還是以上述游戲的情況為例子。假設(shè)當(dāng)前我們要打造的不再是單一的武器,而是需要打造對(duì)應(yīng)的武器和盔甲。同時(shí),武器和盔甲必須成套打造才有相應(yīng)的屬性加成。那么這個(gè)時(shí)候,工廠方法和簡(jiǎn)單工廠就比較難滿足我們的需求了。
針對(duì)這個(gè)情況,我們可以設(shè)計(jì)相應(yīng)的抽象工廠解決。這里我們首先假定套裝有兩套,黑龍?zhí)籽b和紅龍?zhí)籽b。
首先咱們先設(shè)計(jì)一個(gè)抽象的套裝工廠,其兩個(gè)方法分別是生產(chǎn)武器和盔甲。
public abstract class SuitShop {
public abstract Weapon createWeapon();
public abstract Armor createArmor();
}
隨后根據(jù)職業(yè)和套裝指定相應(yīng)的工廠實(shí)現(xiàn)子類。(這里僅僅實(shí)現(xiàn)了戰(zhàn)士的工廠實(shí)現(xiàn)子類,其余角色的子類實(shí)現(xià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();
}
}
除了工廠,我們還要定義對(duì)應(yīng)的黑龍?zhí)籽b和紅龍?zhí)籽b對(duì)應(yīng)的武器和盔甲的子類。
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方法中定義相應(yīng)的邏輯,然后執(zhí)行得到如下結(jié)果。
總的來(lái)說(shuō),抽象工廠主要是針對(duì)多個(gè)類型對(duì)象的時(shí)候使用的方法。但其缺點(diǎn)也很明顯,首先是需要增加較多的類來(lái)實(shí)現(xiàn)相應(yīng)的邏輯。其次是該方式也不符合開(kāi)閉原則,如果需要修改的時(shí)候,是需要對(duì)工廠和對(duì)象都進(jìn)行相應(yīng)的代碼修改的。例如如果需要再增加一個(gè)頭盔,就可能影響到各個(gè)套裝都需要增加對(duì)頭盔的鍛造邏輯的實(shí)現(xiàn)。
總結(jié)
本文介紹了工廠模式對(duì)應(yīng)的三種不同實(shí)現(xiàn)方法,包括**簡(jiǎn)單工廠**、**工廠方法**以及**抽象工廠**。三種實(shí)現(xiàn)方法也各有優(yōu)劣。
-
簡(jiǎn)單工廠,邏輯簡(jiǎn)單,代碼邏輯易懂,但是不符合開(kāi)閉原則,增加工廠需要改動(dòng)相應(yīng)的判斷邏輯。
-
工廠方法,對(duì)于簡(jiǎn)單工廠做了進(jìn)一步的抽象,新增工廠只需要新增加相應(yīng)的工廠類即可,不涉及到工廠判斷的邏輯。但是會(huì)存在多個(gè)工廠的情況下,類的數(shù)目增多的情況。
-
抽象工廠,是對(duì)于工廠方法的進(jìn)一步抽象,其支持同時(shí)生生成多個(gè)對(duì)象。通過(guò)新增加工廠類可以新增加需要生成的組合對(duì)象。但是問(wèn)題在于其也違背了開(kāi)閉原則,當(dāng)需要生成的對(duì)象數(shù)量增多時(shí),相應(yīng)的邏輯需要進(jìn)行修改和增加。