前面我們說了工廠方法模式,當隻需要生産某一種類的時候可以使用。如果我們需要生産多類産品,就可以考慮使用抽象工廠模式。
抽象工廠模式的使用情景如下:
- 系統需要多種産品,但是每次隻需要一組産品。
- 産品種類較固定,産品的組合可能頻繁變化。
說得好像有點雲裡霧裡,是以先看一個例子吧。首先我們先來定義兩組産品接口,一個是調料,一個是食物。
public interface Food {
String getFood();
}
public interface Spice {
String getSpice();
}
然後我們來定義生産食物和調料的抽象工廠。
public interface AbstractFactory {
Spice getSpice();
Food getFood();
}
然後我們定義兩個具體工廠,一個生産蛋糕,一個生産辣條。注意這裡使用了Java 8的Lambda表達式。
public class CakeFactory implements AbstractFactory {
@Override
public Spice getSpice() {
return () -> "糖";
}
@Override
public Food getFood() {
return () -> "蛋糕";
}
}
public class LatiaoFactory implements AbstractFactory {
@Override
public Spice getSpice() {
return () -> "辣椒";
}
@Override
public Food getFood() {
return () -> "辣條";
}
}
然後我們擷取一下蛋糕和辣條。可以看到如果需要擷取某組産品(糖和蛋糕、辣椒和辣條),那麼抽象工廠模式非常适合。而且要建立新的産品組合也很簡單,隻需要實作一個新的具體工廠即可。
public void run() {
AbstractFactory factory = new CakeFactory();
Spice spice = factory.getSpice();
Food food = factory.getFood();
printSpiceAndFood(spice, food);
factory = new LatiaoFactory();
spice = factory.getSpice();
food = factory.getFood();
printSpiceAndFood(spice, food);
}
private static void printSpiceAndFood(Spice spice, Food food) {
System.out.println("調料:" + spice.getSpice() + "," + "食物:" + food.getFood());
}
比如說我們要建立一個新的鹹鴨蛋工廠,也非常簡單。
public class SaltyEggFactory implements AbstractFactory {
@Override
public Spice getSpice() {
return () -> "鹽";
}
@Override
public Food getFood() {
return () -> "鹹鴨蛋";
}
}
那麼抽象工廠模式的缺點是什麼呢?其實從上面的例子中我們也可以看出來了。抽象工廠模式建立新的産品組合非常簡單(實作新的具體工廠),但是如果我們要增加新的産品種類,代碼就需要進行大量更改了。比方說我們現在需要添加一個餐具,那麼上面的抽象工廠類、三個具體類的代碼就必須全部進行更改。在實際情況中,這往往會破壞代碼開發者和使用者之間的協定。
說到這裡,抽象工廠模式的優缺點和使用場景也就呼之欲出了。如果系統中需要多種類型的産品,而産品的種類相對固定,不會出現新類型,這時候就可以使用抽象工廠模式。符合這種情景的都可以使用抽象工廠,例如為軟體更換界面,由于界面的标題欄、菜單欄等元件相對固定,是以這些可以聲明為一個抽象工廠,然後每一中界面樣式為一個具體實作工廠。