用抽象工廠模式開奶茶店
相關概念
- 產品等級結構 :產品等級結構即產品的繼承結構,如一個抽象類是電視機,其子類有海爾電視機、海信電視機、TCL電視機,則抽象電視機與具體品牌的電視機之間構成了一個產品等級結構,抽象電視機是父類,而具體品牌的電視機是其子類。
- 產品族 :在抽象工廠模式中,產品族是指由同一個工廠生產的,位於不同產品等級結構中的一組產品,如海爾電器工廠生產的海爾電視機、海爾電冰箱,海爾電視機位於電視機產品等級結構中,海爾電冰箱位於電冰箱產品等級結構中。
參考:https://design-patterns.readthedocs.io/zh_CN/latest/creational_patterns/abstract_factory.html
定義
抽象工廠模式提供一個接口,用於創建相關或依賴對象的產品族,而不需要明確指定具體類。
這個定義可能一下看不太懂,結合後面例子就容易理解很多。
應用場景
當工廠需要生產出產品族時,使用抽象工廠模式。當工廠不生產產品族而只負責生產一類產品時抽象工廠模式退化爲工廠方法模式。
比如頁面的風格變換,往往需要多個組件的同時修改,此時用抽象工廠模式,則每一個具體工廠負責一種風格,替換風格只需替換具體工廠即可。
例子
我們用奶茶做例子。
一個奶茶製造工廠,它可以同時提供牛奶和茶,但不同地方的奶茶工廠選用的牛奶和茶的品種都不一樣,因爲不是所有的牛奶都叫特侖蘇。一點點和喜茶從不同額奶茶工廠中拿到奶茶原料,我們用程序模擬這個情況,下面是uml類圖。
Milk接口定義了牛奶產品等級結構的方法,Tea解耦定義了茶產品等級結構的方法。MilkTeaFactory接口定義了奶茶工廠的方法,方法返回的值類型是抽象接口,所以調用的客戶在編譯期並不知道返回的茶和奶的具體類型是什麼,只有在運行時運用多態的技術才能知道具體是哪種奶和茶。這就實現了針對接口編程而不是針對具體編程。
下面是代碼
Tea.java
package priv.mxz.design_pattern.abstract_factory_pattern;
interface Tea {
String getType();
}
class GreenTea implements Tea{
@Override
public String getType() {
return "綠茶";
}
}
class BlackTea implements Tea{
@Override
public String getType() {
return "紅茶";
}
}
Milk.java
package priv.mxz.design_pattern.abstract_factory_pattern;
interface Milk {
String getCompany();
}
class MengniuMilk implements Milk{
@Override
public String getCompany() {
return "蒙牛公司";
}
}
class YiliMilk implements Milk{
@Override
public String getCompany() {
return "伊利公司";
}
}
MilkTeaFactory.java
package priv.mxz.design_pattern.abstract_factory_pattern;
interface MilkTeaFactory {
Tea getTea();
Milk getMilk();
}
class MilkTeaFactoryA implements MilkTeaFactory{
@Override
public Tea getTea() {
return new GreenTea();
}
@Override
public Milk getMilk() {
return new MengniuMilk();
}
}
class MilkTeaFactoryB implements MilkTeaFactory{
@Override
public Tea getTea() {
return new BlackTea();
}
@Override
public Milk getMilk() {
return new YiliMilk();
}
}
MilkTeaShop.java
package priv.mxz.design_pattern.abstract_factory_pattern;
class MilkTeaShop{
private MilkTeaFactory milk_tea_factory;
private String shop_name;
public MilkTeaShop(MilkTeaFactory mtf,String shop_name){
milk_tea_factory=mtf;
this.shop_name=shop_name;
}
public void makeMilkTea(){
System.out.println("MilkTeaShop "+ shop_name+ " make a milk tea with ");
System.out.println(milk_tea_factory.getMilk().getCompany());
System.out.println(milk_tea_factory.getTea().getType());
}
}
AbstractFactoryPattern.java
package priv.mxz.design_pattern.abstract_factory_pattern;
public class AbstractFactoryPattern {
public static void main(String[] args) {
MilkTeaShop yidiandian=new MilkTeaShop(new MilkTeaFactoryA(), "一點點");
MilkTeaShop xicha=new MilkTeaShop(new MilkTeaFactoryB(),"喜茶");
yidiandian.makeMilkTea();
xicha.makeMilkTea();
}
}
結果
MilkTeaShop 一點點 make a milk tea with
蒙牛公司
綠茶
MilkTeaShop 喜茶 make a milk tea with
伊利公司
紅茶
AbstractFactoryPattern.java中有函數入口,可以看到,不同的奶茶店通過綁定不同的奶茶工廠就得到了不同的牛奶和茶。
優缺點
優點:
抽象工廠模式很好地解釋了什麼是面向接口編程,工廠處理的是產品的抽象類或接口,客戶也是針對抽象工廠來編程。
添加新的工廠與產品非常方便,不需要修改已有的工廠類和產品類,符合開閉原則
缺點:
工廠生產出來的產品族種類難改變,如果想要新生產另一類產品,則需要修改抽象工廠接口,同時修改所有具體工廠的實現
總結
抽象工廠模式是工廠模式系列的最終版,工廠可以生產出一個產品族,當只生產一種產品時,抽象工廠模式退化爲工廠方法模式。抽象工廠模式的抽象在於無論是工廠還是客戶都是面向接口編程,不涉及具體的類。抽象工廠模式添加新的工廠生產相同品種的產品很容易,但要工廠生產新類型的產品則很困難。