《Head First 設(shè)計(jì)模式》 學(xué)習(xí)筆記,碼云同步更新中
如有錯(cuò)誤或不足之處,請(qǐng)一定指出,謝謝~
目錄
查看其它設(shè)計(jì)模式筆記,點(diǎn)這里→設(shè)計(jì)模式筆記匯總
抽象工廠模式(Abstract Factory Pattern)
- 定義:
- 提供一個(gè)創(chuàng)建一系列相關(guān)或相互依賴(lài)對(duì)象的接口,用于創(chuàng)建相關(guān)或依賴(lài)對(duì)象的家族,而無(wú)須指定它們具體的類(lèi)。
- 結(jié)構(gòu):
- AbstractFactory:抽象工廠
- ConcreteFactory:具體工廠
- AbstractProduct:抽象產(chǎn)品
- ConcreteProduct:具體產(chǎn)品
- 對(duì)比工廠方法和簡(jiǎn)單工廠:
- 工廠方法模式針對(duì)的是一個(gè)產(chǎn)品等級(jí)結(jié)構(gòu),而抽象工廠模式則需要面對(duì)多個(gè)產(chǎn)品等級(jí)結(jié)構(gòu),一個(gè)工廠等級(jí)結(jié)構(gòu)可以負(fù)責(zé)多個(gè)不同產(chǎn)品等級(jí)結(jié)構(gòu)中的產(chǎn)品對(duì)象的創(chuàng)建 。當(dāng)一個(gè)工廠等級(jí)結(jié)構(gòu)可以創(chuàng)建出分屬于不同產(chǎn)品等級(jí)結(jié)構(gòu)的一個(gè)產(chǎn)品族中的所有對(duì)象時(shí),抽象工廠模式比工廠方法模式更為簡(jiǎn)單、有效率。
- 當(dāng)抽象工廠模式中每一個(gè)具體工廠只創(chuàng)建一個(gè)產(chǎn)品對(duì)象,那抽象工廠模式就退化為工廠方法模式。
- 當(dāng)工廠方法模式的抽象工廠與具體工廠合并,提供一個(gè)統(tǒng)一的工廠來(lái)創(chuàng)建產(chǎn)品對(duì)象,那工廠方法模式就退化為簡(jiǎn)單工廠。
- 優(yōu)點(diǎn):
- 新增加具體工廠和產(chǎn)品族很方便,符合“開(kāi)閉”原則
- 符合“依賴(lài)倒置”原則
- 高層模塊不需要關(guān)心低層模塊的具體實(shí)現(xiàn),只需要關(guān)心抽象,關(guān)心工廠。
- 抽象工廠可以約束產(chǎn)品族的特性(比如配比,芝士與奶油1:2)
- 缺點(diǎn):
- 對(duì)于產(chǎn)品族的擴(kuò)展非常困難。抽象工廠中定義了有可能會(huì)被創(chuàng)建的所有產(chǎn)品的方法。如果新增產(chǎn)品,就必須要修改抽象類(lèi)和所有實(shí)現(xiàn)類(lèi)。(“開(kāi)閉原則”的傾斜性)
- 使用場(chǎng)景:
- 系統(tǒng)中有多個(gè)產(chǎn)品族,每次只使用其中某一族
- 系統(tǒng)需要約束屬于同一產(chǎn)品族的產(chǎn)品必須在一起使用
- 案例:
- 簡(jiǎn)單工廠:顧客點(diǎn)單時(shí),需要根據(jù)菜名創(chuàng)建出各種不同種類(lèi)的披薩。這些披薩都源自同一個(gè)披薩基類(lèi),不過(guò)各自有自己的口味實(shí)現(xiàn)。而我們創(chuàng)建具體的披薩對(duì)象時(shí),只需要提供名字,不需要知道它們是如何創(chuàng)建的。這時(shí)就可以用到簡(jiǎn)單工廠,傳遞一個(gè)參數(shù)給工廠類(lèi),返回一個(gè)相應(yīng)的披薩對(duì)象。
- 工廠方法:這時(shí)我們披薩店要擴(kuò)張了,但在各個(gè)省可能會(huì)有不同的制作方法。我們希望披薩在披薩口味上加盟店有自己的決定權(quán)。但在制作流程上要受到總店的控制,比如必須使用我們品牌的盒子來(lái)裝披薩等等。
這時(shí)候就需要我們用工廠方法模式來(lái)改造了。 - ok,又有新需求了。有些加盟店會(huì)使用廉價(jià)的原料來(lái)增加利潤(rùn)。你想要更多的質(zhì)量控制——建造一家原料工廠,將原料運(yùn)送到加盟店。同時(shí)問(wèn)題也出現(xiàn)了,各地加盟店的披薩口味不同,原料也是不一樣的。這時(shí)候抽象工廠模式就有用武之地了。
- 代碼:
/**
* 披薩原料抽象工廠
**/
public interface PizzaIngredientFactory {
Cheese createCheese();
Pepperoni createPepperoni();
}
/**
* 意大利香腸原料
**/
public interface Pepperoni {
// 略...
}
/**
* 芝士原料
**/
public interface Cheese {
// 略...
}
/**
* 上海用的芝士
**/
public class SHCheese implements Cheese {
// 略...
}
/**
* 上海用的香腸
**/
public class SHPepperoni implements Pepperoni {
// 略...
}
/**
* 披薩 抽象
**/
public abstract class Pizza {
String name;
public Cheese cheese;
public Pepperoni pepperoni;
/**
* 準(zhǔn)備
* 申明為抽象方法,子類(lèi)需自行實(shí)現(xiàn)原料準(zhǔn)備
*/
public abstract void prepare();
/**
* 烘焙
*/
public void bake() {
System.out.println("烘焙中...");
}
/**
* 切片
*/
public void cut() {
System.out.println("切片中...");
}
/**
* 裝盒
*/
public void box() {
System.out.println("裝盒中...");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
/**
* 芝士披薩
**/
public class CheesePizza extends Pizza {
PizzaIngredientFactory ingredientFactory;
/**
* 構(gòu)造器注入工廠
*
* @param ingredientFactory
*/
public CheesePizza(PizzaIngredientFactory ingredientFactory) {
this.ingredientFactory = ingredientFactory;
}
/**
* pizza無(wú)需關(guān)心到底是什么類(lèi)型的原料工廠,只要是原料工廠就行
*/
@Override
public void prepare() {
System.out.println("原料準(zhǔn)備中");
// 為基類(lèi)屬性賦值
cheese = ingredientFactory.createCheese();
pepperoni = ingredientFactory.createPepperoni();
}
}
/**
* 披薩店 抽象
**/
public abstract class PizzaStore {
public Pizza orderPizza(String type) {
// 把創(chuàng)建披薩方法從簡(jiǎn)單工廠拿回來(lái)
Pizza pizza = createPizza(type);
pizza.prepare();
pizza.bake();
pizza.cut();
pizza.box();
System.out.println(pizza.getName() + "制作完成");
return pizza;
}
/**
* 將實(shí)例化披薩的責(zé)任移到抽象方法中,這個(gè)方法就等同于一個(gè)工廠
* 子類(lèi)通過(guò)這個(gè)方法來(lái)執(zhí)行對(duì)象實(shí)例化邏輯,達(dá)到超類(lèi)和子類(lèi)解耦的目的
*/
abstract Pizza createPizza(String type);
}
/**
* 上海加盟店
**/
public class SHPizzaStore extends PizzaStore {
/**
* 上海披薩原料工廠
*/
private PizzaIngredientFactory ingredientFactory = new SHPizzaIngredientFactory();
private Pizza pizza;
@Override
protected Pizza createPizza(String type) {
if ("cheese".equals(type)) {
pizza = new CheesePizza(ingredientFactory);
pizza.setName("上海芝士披薩");
return pizza;
} else if ("veggie".equals(type)) {
// 略...
return null;
}
return null;
}
}
/**
* 測(cè)試類(lèi)
**/
public class Test {
public static void main(String[] args) {
SHPizzaStore shPizzaStore = new SHPizzaStore();
shPizzaStore.orderPizza("cheese");
}
}
結(jié)果:
原料準(zhǔn)備中
原料:上海芝士
原料:上海臘腸
烘焙中...
切片中...
裝盒中...
上海芝士披薩制作完成