用烤肉來看工廠模式(上)
目錄
基本物件介紹
最重要的肉
public abstract class Meat { private String name; private int oz; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getOz() { return oz; } public void setOz(int oz) { this.oz = oz; } public Meat(String name) { this.name = name; } public Meat(){ } }
豬肉
public class Pork extends Meat{ public Pork(String name) { super(name); } }
你抱著期待的心到全聯,準備大買特買,發現全聯有出烤肉組合包,立馬手刀購買
全聯
public class PXMarket { // 烤肉組合包 public static void barbecueItemSet(){ buy("烤肉架"); buy("木炭"); buy(orderBarbecue("牛肉").getName()); buy(orderBarbecue("豬肉").getName()); buy(orderBarbecue("雞肉").getName()); } static Meat orderBarbecue(String meatType){ if(meatType.equals("牛肉")){ return new Beef("和牛"); }else if(meatType.equals("雞肉")){ return new Chicken("土雞"); }else { return new Pork("伊比利豬"); } } public static void buy(String item){ System.out.println("買到"+item+"了"); } }
買完回家,開始烤肉
//程式進入點 public static void main(String[] args) { PXMarket.barbecueItemSet(); System.out.println("回家開烤"); }

Figure 1. 第一次烤肉結果
簡單工廠模式
public class SimpleMeatFactory { public static Meat orderBarbecue(String meatType){ if(meatType.equals("牛肉")){ return new Beef("和牛"); }else if(meatType.equals("雞肉")){ return new Chicken("土雞"); }else { return new Pork("伊比利豬"); } } }
全聯的服務只剩單純的組合包功能,將點肉服務外包給簡單肉工廠。
public class PXMarket { // 烤肉組合包 public static void barbecueItemSet(){ buy("烤肉架"); buy("木炭"); buy(SimpleMeatFactory.orderBarbecue("牛肉").getName()); buy(SimpleMeatFactory.orderBarbecue("豬肉").getName()); buy(SimpleMeatFactory.orderBarbecue("雞肉").getName()); } public static void buy(String item){ System.out.println("買到"+item+"了"); } }
簡單工廠負責管理物件的創造,如果client端要取得物件,只要給簡單工廠正確的參數即可。
想吃烤鯖魚
吃完了烤肉以後,突然想吃烤鯖魚,你又到全聯點肉,簡單肉工廠為了你加了魚肉到商品列。
public class Fish extends Meat{ public Fish(String name) { super(name); } }
並將魚肉放到菜單上
public class SimpleMeatFactory { public static Meat orderBarbecue(String meatType){ if(meatType.equals("牛肉")){ return new Beef("和牛"); }else if(meatType.equals("雞肉")){ return new Chicken("土雞"); }else if(meatType.equals("魚肉")){ return new Fish("鯖魚"); }else { return new Pork("伊比利豬"); } } }
全聯新增賣魚服務
public static void buyFish(){ buy(SimpleMeatFactory.orderBarbecue("魚肉").getName()); }
買完魚開烤
//程式進入點 public static void main(String[] args) { PXMarket.buyFish(); System.out.println("回家開烤"); }
全聯覺得這樣下去不行,每次有客人想要點不同種的肉,它們都要及時修改商品列和菜單,並且這樣違反了OCP法。
工廠方法模式
全聯決定與各自的肉工廠合作,於是全聯訂了一個介面,讓想要合作的肉工廠來找它們簽約。
public interface MeatMethodFactory { Meat orderMeat(); }
之前合作的肉工廠紛紛來簽約
牛肉工廠
public class BeefFactory implements MeatMethodFactory{ @Override public Meat orderMeat() { return new Beef("和牛"); } }
雞肉工廠
public class ChickenFactory implements MeatMethodFactory{ @Override public Meat orderMeat() { return new Chicken("土雞"); } }
豬肉工廠
public class PorkFactory implements MeatMethodFactory{ @Override public Meat orderMeat() { return new Pork("伊比利豬"); } }
魚肉工廠
public class FishFactory implements MeatMethodFactory{ @Override public Meat orderMeat() { return new Fish("鯖魚"); } }
簽約完以後,全聯準備了一台iphone,專門為了跟工廠叫肉。
public static Meat callFactory(MeatMethodFactory factory){ return factory.orderMeat(); }
之前的買魚服務,只要呼叫對應廠商就可以叫魚了。
public static void buyFish(){ FishFactory fishFactory = new FishFactory(); buy(callFactory(fishFactory).getName()); }
工廠方法模式定義了一個建立物件的介面,但由子類決定要實例化的類別為何。工廠方法讓類別把 實例化 的動作推遲到了子類
抽象工廠模式
全聯後來決定分成國產肉工廠和進口肉工廠,每間肉工廠必須至少供應牛、雞、豬、魚,於是它們又訂了新的介面。
public interface AbstractFactory { public Beef supplyBeef(); public Chicken supplyChicken(); public Pork supplyPork(); public Fish supplyFish(); }
國產肉工廠
public class DomesticFactory implements AbstractFactory{ @Override public Beef supplyBeef() { return new Beef("國產牛肉"); } @Override public Chicken supplyChicken() { return new Chicken("國產雞肉"); } @Override public Pork supplyPork() { return new Pork("國產豬肉"); } @Override public Fish supplyFish() { return new Fish("國產鯖魚"); } }
進口肉工廠
public class ImportFactory implements AbstractFactory{ @Override public Beef supplyBeef() { return new Beef("進口和牛"); } @Override public Chicken supplyChicken() { return new Chicken("進口雞肉"); } @Override public Pork supplyPork() { return new Pork("進口豬肉"); } @Override public Fish supplyFish() { return new Fish("進口鯖魚"); } }
烤肉包組合
public static void barbecueItemSet(){ DomesticFactory domesticFactory = new DomesticFactory(); buy("烤肉架"); buy("木炭"); buy(domesticFactory.supplyBeef().getName()); buy(domesticFactory.supplyChicken().getName()); buy(domesticFactory.supplyPork().getName()); }
耶!!吃到國產豬肉了,不用擔心吃到有病毒的烤肉了

Figure 2. 最後一次烤肉結果
抽象工廠模式定義一個創建 產品族 的介面,產品族裡面每個產品的具體類別由繼承抽象工廠的實體工廠決定。