簡單工廠模式
由一個工廠對象決定創(chuàng)建出哪一種產(chǎn)品類的實例计寇。屬于創(chuàng)建型模式常拓,但不屬于GoF(23種設(shè)計模式)。
舉例:首先建立一個接口類毛秘,名為Animal,并在其中定義一個name()方法。
public interface Animal {
public void name();
}
分別建立Cat叫挟、Dog艰匙、Bird實體類并實現(xiàn)Animal。
public class Cat implements Animal{
public void name() {
System.out.println("A cat");
}
}
public class Dog implements Animal {
public void name() {
System.out.println("A dog");
}
}
public class Dog implements Animal {
public void name() {
System.out.println("A dog");
}
}
建立工廠類抹恳,名為AnimalFactory员凝,定義create()方法,傳入?yún)?shù)為想要創(chuàng)建對象的實體類
public class AnimalFactory {
public Animal create(Class clazz) {
if (clazz != null) {
try {
return (Animal) clazz.getDeclaredConstructor().newInstance(); //Java 9 以后不推薦直接使用clazz.newInstance()創(chuàng)建對象
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
}
這樣一個簡單工廠模式的樣例就成型了奋献,我們來新建一個測試類健霹,測試AnimalFactory工廠類能創(chuàng)建出我們指定的對象。
public class AnimalFactoryTest {
public static void main(String[] args) {
AnimalFactory factory = new AnimalFactory();
Animal animal = factory.create(Cat.class);
animal.name();
}
}
輸出結(jié)果如下所示:
A cat
優(yōu)點:簡單工廠模式用戶只需要傳入正確的參數(shù)就可以獲取所需要的對象瓶蚂,無須知道它的創(chuàng)建細節(jié)糖埋。
缺點:工廠類的職責(zé)過于沉重,當添加新產(chǎn)品的時候窃这,需要修改工廠類的判斷邏輯瞳别,違反了開閉原則。不利于擴展過于復(fù)雜的產(chǎn)品結(jié)構(gòu)杭攻。
總結(jié):簡單工廠模式的適用場景有限祟敛,只適用于創(chuàng)建對象數(shù)量比較少,創(chuàng)建邏輯不復(fù)雜而且過程比較穩(wěn)定的場景兆解。
工廠方法模式
定義一個創(chuàng)建產(chǎn)品對象的工廠接口馆铁,讓實現(xiàn)這一個接口的工廠類來決定實例化哪種產(chǎn)品對象,將類的實例化工作推遲到子類中完成锅睛。屬于創(chuàng)建型模式埠巨,屬于GoF。其核心結(jié)構(gòu)有四個角色:抽象工廠衣撬、具體工廠乖订、抽象產(chǎn)品、具體產(chǎn)品具练。
舉例:抽象產(chǎn)品和具體產(chǎn)品我們依舊使用上面所建立的Animal乍构、Cat、Dog和Bird扛点。
接下來我們來建立抽象工廠類哥遮,名為IAnimalFactory,它提供一個名為create()的方法
public interface IAnimalFactory {
Animal create();
}
分別建立CatFactory陵究、DogFactory眠饮、BirdFactory實現(xiàn)抽象工廠類IAnimalFactory
public class CatFactory implements IAnimalFactory {
public Animal create() {
return new Cat();
}
}
public class DogFactory implements IAnimalFactory {
public Animal create() {
return new Dog();
}
}
public class BirdFactory implements IAnimalFactory {
public Animal create() {
return new Bird();
}
}
建立測試類AnimalFactoryTest來進行測試
public class AnimalFactoryTest {
public static void main(String[] args) {
IAnimalFactory factory = new CatFactory();
Animal animal = factory.create();
animal.name();
}
}
輸出結(jié)果如下所示:
A cat
優(yōu)點:用戶只需關(guān)心所需產(chǎn)品對應(yīng)的工廠,無需關(guān)心創(chuàng)建細節(jié)铜邮。加入新產(chǎn)品符合開閉原則仪召,提高了系統(tǒng)的可擴展性寨蹋。
缺點:類的個數(shù)容易過多,增加了代碼結(jié)構(gòu)的復(fù)雜度扔茅。增加了系統(tǒng)的抽象性和理解難度已旧。
總結(jié):工廠方法模式是簡單工廠模式的衍生,解決了許多簡單工廠模式的問題,完全實現(xiàn)開閉原則召娜,易于擴展运褪。
工廠方法經(jīng)常用在以下兩種情況中:
第一種情況是對于某個產(chǎn)品,調(diào)用者清楚地知道應(yīng)該使用哪個具體工廠服務(wù)玖瘸,實例化該具體工廠秸讹,生產(chǎn)出具體的產(chǎn)品來。Java Collection中的iterator() 方法即屬于這種情況雅倒。
第二種情況璃诀,只是需要一種產(chǎn)品,而不想知道也不需要知道究竟是哪個工廠為生產(chǎn)的文虏,即最終選用哪個具體工廠的決定權(quán)在生產(chǎn)者一方,它們根據(jù)當前系統(tǒng)的情況來實例化一個具體的工廠返回給使用者殖演,而這個決策過程這對于使用者來說是透明的年鸳。
抽象工廠模式
隸屬于設(shè)計模式中的創(chuàng)建型模式,用于產(chǎn)品族的構(gòu)建搔确。提供一個創(chuàng)建一系列相關(guān)或相互依賴對象的接口,無需指定他們具體的類膳算。
首先我們先來了解一下產(chǎn)品族和產(chǎn)品等級結(jié)構(gòu),如下圖所示涕蜂,方塊、圓机隙、三角各代表一種產(chǎn)品蜘拉,不同的顏色對應(yīng)不同的型號(也可理解為品牌)。同一品牌下的不同產(chǎn)品構(gòu)成一個產(chǎn)品族有鹿,同種產(chǎn)品的不同品牌構(gòu)成一個產(chǎn)品等級結(jié)構(gòu)旭旭。
我們來看一個例子骤肛,手機斑鼻、平板和筆記本這三種對象,我們可以把他們看成是一個產(chǎn)品族稳吮,針對于這一個產(chǎn)品族我們會有很多的品牌,比如蘋果稍味、華為和聯(lián)想咸产,他們?nèi)齻€針對于每一項產(chǎn)品又組成一個產(chǎn)品等級結(jié)構(gòu)。
我們就可以通過抽象工廠方法模式來構(gòu)建這樣一個工廠仲闽。
我問先根據(jù)產(chǎn)品建立對應(yīng)的抽象產(chǎn)品類脑溢,分別為Phone、Pad和Laptop,這里只簡單的添加了一個name方法
public interface Phone {
void name();
}
public interface Phone {
void name();
}
public interface Laptop {
void name();
}
然后我們建立一個頂層的抽象工廠類赖欣,名為BeanFactory,在其中定義三個方法屑彻,分別用來創(chuàng)建手機、平板和筆記本對象顶吮。
public interface BeanFactory {
//生成手機
Phone createPhone();
//生成平板
Pad createPad();
//生成筆記本
Laptop createLaptop();
}
這時我們需要創(chuàng)建產(chǎn)品的具體實現(xiàn)類社牲,這里以蘋果產(chǎn)品為例,需要分別對Phone悴了、Pad和Laptop進行實現(xiàn)搏恤,這里編寫了IPhone、IPad和MacBook三個類
public class IPhone implements Phone {
public void name() {
System.out.println("IPhone");
}
}
public class IPad implements Pad {
public void name() {
System.out.println("IPad");
}
}
public class MacBook implements Laptop {
public void name() {
System.out.println("MacBook");
}
}
然后我們來編寫蘋果工廠的具體實現(xiàn)類湃交,名為AppleFactory熟空,來實現(xiàn)BeanFactory
public class AppleFactory implements BeanFactory {
public Phone createPhone() {
return new IPhone();
}
public Pad createPad() {
return new IPad();
}
public Laptop createLaptop() {
return new MacBook();
}
}
我們來測試以下工廠是否可以正常工作,編寫測試類BeanFactoryTest
public class BeanFactoryTest {
public static void main(String[] args) {
BeanFactory factory = new AppleFactory();
factory.createPhone().name();
factory.createPad().name();
factory.createLaptop().name();
}
}
輸出為:
IPhone
IPad
MacBook
這個過程中我們發(fā)現(xiàn)抽象工廠模式是對擴展開放的搞莺,但是如果新添加一種產(chǎn)品息罗,勢必要修改頂層的抽象工廠類,沒有做到對修改關(guān)閉才沧,也就違反了開閉原則迈喉。
適用場景:
1.客戶端(應(yīng)用層)不關(guān)注產(chǎn)品類實例如何被實現(xiàn)、創(chuàng)建的細節(jié)温圆。
2.一系列相關(guān)的產(chǎn)品對象(同一產(chǎn)品族)一起使用創(chuàng)建對象時需要大量重復(fù)的代碼
3.提供一個已經(jīng)確定產(chǎn)品類的庫挨摸,所有的產(chǎn)品以同樣的接口出現(xiàn),使得客戶端不依賴于具體實現(xiàn)
優(yōu)點:具體產(chǎn)品的實現(xiàn)代碼被隔離岁歉,使得調(diào)用者無需關(guān)心創(chuàng)建細節(jié)得运。將一個系列的產(chǎn)品族統(tǒng)一到一起進行創(chuàng)建。
缺點:規(guī)定了所有可能被創(chuàng)建的產(chǎn)品的集合刨裆,產(chǎn)品族中擴展新的產(chǎn)品變得困難澈圈,需要修改抽象工廠中的接口。增加了系統(tǒng)的抽象性和理解難度帆啃。