iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 12
0

本文同步分享於個人blog

  • 定義


提供一個建立一系列相關或者相互依賴物件的介面,而無需指定它們具體的類。

簡單來說就是

  1. 提供一個介面,用來建立相關的物件系列
  2. 實作不同的抽象工廠,將提供不同的物件系列,內容以工廠方法做實作。
  3. 決定了工廠就等於決定了會取得的物件系列。
  • 回顧 Factory Method Pattern


前一篇用開餐廳的例子介紹了Sample Factory Pattern以及Factory Method Pattern。這裡我們用開好的餐廳,來接著介紹Abstract Factory Pattern。

首先我們先來回顧一下Factory Method的範例


interface CookMeal{
    void cook();
    void delivery();
}
interface MealFactory{
  public CookMeal createMeal();
}
class SteakFactory implements MealFactory{
  public CookMeal createMeal(){
    return new Steak();
  }
}
class Steak implements CookMeal{

  @Override
  public void cook(){
    System.out.println("把牛排煮熟");
  };
  @Override
  public void delivery(){
    System.out.println("送牛排");
  };
}

class Restaurant{
  private MealFactory factory;

  public Restaurant (MealFactory factory){
    this.factory = factory;
  }

  public CookMeal mealOrder(){
    CookMeal meal;

    meal = factory.createMeal();

    meal.cook();
    meal.delivery();

    return meal;
  }
}
public class MyRestaurant {
    public static void main(String args[]) {
     
        Restaurant rSteak = new Restaurant(new SteakFactory());
        rSteak.mealOrder();

    }
}

output

把牛排煮熟
送牛排

這是我們前一篇使用的範例,很明顯的工廠方法是針對一種物件在做處理。那假如我想要拿到的是一組多個物件呢?也就是說如果要再細分套餐的內容物,那每種原料,都必須建立一個工廠。如台式牛排配台式牛排醬,義式牛排配義式牛排醬。

項目 台式 義式
牛排 台式牛排 義式牛排
豬排 台式豬排 義式豬排

所以如果是這樣擴充的話,會增加許多的工廠。而抽象工廠模式便可以解決這類的問題。不需要每種產品都開一個工廠,可以開一間台式餐廳,一間義式餐廳。而兩間餐廳上頭的企業就是餐廳的抽象工廠。

註:如對Factory Method不太熟悉,的可以參考 開一間餐廳 - Factory Pattern

  • Abstract Factory Pattern 成員


老樣子,在使用Prototype Pattern之前,還是得先認識其中的成員

成員 功用
Abstract Factory 提供建立產品的接口,包含多個建立產品的方法,可建立不同產品。
Concrete Factory 主要是實作抽象工廠中的抽象方法,完成實體產品的建立。
Product 定義產品的規範、特性及功能,可以有多個抽象產品。
ConcreteProduct 實作抽象產品,實體由工廠建立,和實體工廠是多對一的關係。

可以看看抽象工廠的UML圖。

AF1

由圖上可以了解,實體工廠實作抽象工廠後,實體工廠去取得實體產品,來完成整體流程。

  • Abstract Factory Pattern實作


現在來試試抽象工廠的做法。首先先定義原料(Ptoduct)的抽象類別:

interface Ingredient {
    public void getSauce();
}

再來建立台式及義式原料的實體(ConcreteProduct)並實作原料的抽象類別。

class TWIngredient implements Ingredient {
    public void getSauce() {
        System.out.println("淋上台式醬料!");
    }
}
class ITIngredient implements Ingredient {
    public void getSauce() {
        System.out.println("淋上義式醬料");
    }
}

接著我們要修改Restaurant(Abstract Factory)的類別,定義方法及流程。我們要出一個餐,需要肉跟原料。所以寫一個mealOrder的方法製作餐點,定義createMeal以及getIngredient取得肉及原料。

abstract class Restaurant{

    public CookMeal mealOrder(String type){
    CookMeal meal;
    Ingredient ingredient;

    meal = createMeal(type);
    ingredient = getIngredient();

    meal.cook();
    ingredient.getSauce();
    return meal;
    }
    abstract CookMeal createMeal(String type); // 定義方法
    abstract Ingredient getIngredient(); // 定義方法
}

最後將實體工廠(Concrete Factory)建立起來,分別有台式及義式的餐廳。肉類藉由if-else判斷,而原料就看是哪種風格的餐廳,就建立對應的原料實體。

class TWRestaurant extends Restaurant {
   @Override
   public CookMeal createMeal(String type){  // 實作方法
        CookMeal meal = null;
        if("Steak".equals(type)) {
            meal = new Steak();
        } else if ("Pork".equals(type)){
            meal = new Pork();
        }
        return meal;
   }
   @Override
   public Ingredient getIngredient(){  // 實作方法
        Ingredient ingredient = new TWIngredient();
        return ingredient;
   }
}
class ITRestaurant extends Restaurant {
   @Override
   public CookMeal createMeal(String type){  // 實作方法
        CookMeal meal = null;
        if("Steak".equals(type)) {
            meal = new Steak();
        } else if ("Pork".equals(type)){
            meal = new Pork();
        }
        return meal;
   }
    public Ingredient getIngredient(){  // 實作方法
        Ingredient ingredient = new ITIngredient();
        return ingredient;
   }
}
public class MyRestaurant {
   public static void main(String[] args) {
        Restaurant rSteak = new TWRestaurant();
        rSteak.mealOrder("Steak");
        
        Restaurant rPork = new ITRestaurant();
        rPork.mealOrder("Pork");
   }
}

output

把牛排煮熟
淋上台式醬料!
把豬排煮熟
淋上義式醬料

可以看到MyRestaurant內,只要選擇哪種風格特餐聽,並將想要的餐點填入,就可以取得對應的餐點。最後來看一下範例的UML圖。

從圖上可以了解,需要什麼食材,由餐廳自己決定。這樣當有第三間是綜合風味餐廳,他就看已將所有的引進所有的食材,提升了整體開發的靈活性。

  • 小結


比較工廠方法Factory Method Pattern與抽象工廠Abstract Factory Pattern
抽象工廠:利用物件的合成,集結一些相關的產品,而在實體工廠使用工廠方法來實作要產出的產品。
工廠方法:由繼承來的次類別來決定要產生哪種實體產品,其主要目的是將客戶從實體型態中鬆綁。
Abstract Factory Pattern的目標
  1. 提供一個介面,用來建立相關的物件系列
  2. 實作不同的抽象工廠,將提供不同的物件系列,內容以工廠方法做實作。
  3. 決定了工廠就等於決定了會取得的物件系列。
Abstract Factory Pattern的優缺點
優點
1. 建立新產品系列時不需要修改原本的程式碼。
缺點
1. 產品系列要增加新產品時,所有的工廠類別都需要修改。
  • 範例程式碼


範例1:Factory Method Pattern
範例2:Abstract Factory Pattern

  • References


Java設計模式—工廠方法模式&抽象工廠模式
工廠模式 - 抽象工廠模式 (Abstract Factory Pattern)
設計模式-Abstract Factory抽象工廠模式


上一篇
[Day11] 工廠模式 | Factory Pattern
下一篇
[Day13] 生成器模式 | Builder Pattern
系列文
從生活中認識Design Pattern30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言