--- tags: Design Pattern,Creational Pattern title: Abstract Factory(5) --- {%hackmd Sy5Quc5JY %} ## <font color="#F59F00">**Abstract Factory (5)**</font> * <font color="#92d1ff">**Factory Method 的限制**</font> ==**工廠方法 FactoryMethod 只能創造一個物件**==,像是 `Pizza` 但如果我們想要更加細分創造的東西,比如說 `Pizza` 所需原料 : `Dough`、`Sauce`、`Cheese` ... ,如果我們工廠方法的話,每一個原料都要創一個工廠。 * **Example** ```java public abstract class PizzaStore { public abstract Pizza createPizza(String type); public Pizza orderPizza(String type) { Pizza pizza = createPizza(type); pizza.prepare(); pizza.cook; return pizza; } } public class NewYorkPizzaStore extends PizzaStore { public createPizza(String type) { DoughFactory doughFactory = new NewYorkDoughFactory(); SauceFactory sauceFactory = new NewYorkSauceFactory(); CheeseFactory cheeseFactory = new NewYorkCheeseFactory(); if(type.equals("cheese")) { return new NewYorkCheesePizza( doughFactory, sauceFactory, cheeseFactory); } else if(type.equals("veggie")) { return new NewYorkVeggiePizza( doughFactory, sauceFactory, cheeseFactory); } else if(type.equals("clam")) { return new NewYorkClamPizza( doughFactory, sauceFactory, cheeseFactory); } else if(type.equals("pepperoni")) { return new NewYorkPepperoniPizza( doughFactory, sauceFactory, cheeseFactory); } else { return null; } } } ``` 這個例子就是 NewYork : `DoughFactory` 、 `SauceFactory`、 `CheeseFactory` Chicago : `DoughFactory` 、 `SauceFactory`、 `CheeseFactory` **因為每個工廠方法只能生產一個產品** 這樣太難 maintain 了,**所以我們把相關的產品 : `NewYorkDoughFactory` 、 `NewYorkSauceFactory` 、 `NewYorkCheeseFactory` ,組成一個產品族,交給一個工廠來生產,也就是抽象工廠。** <br><span style="display:block;text-align:center;"><img src="https://www.jyt0532.com/public/abstractfactory1.png" width="750" height="650"></img></span><br> 抽象的 `PizzaIngredientFactory` 定義了每個原料工廠需要建立的物件的介面,每個繼承了 `PizzaIngredientFactory` 的具體工廠,都乖乖執行所有需要建立的物件。 ==**其實也就是工廠的責任從產生一個產品變成產生一個產品族(所有所需的產品)**== * **Example** 1. 產生一個房子的所有家具 : 沙發、電視、桌子、電風扇... 2. 產生一個武士的所有配件 : 佩刀、盔甲、鞋子、手套... * <font color="#92d1ff">**產品等級結構 product hierarchical structure 產品族 product family**</font> * <font color="#98c37a">**product hierarchical structure**</font> 比如說抽象類 `Dough` 子類別有 `NewYorkDough` 、 `ChicagoDough` ,這三個形成了一個 product hierarchical structure * <font color="#98c37a">**product family**</font> 同一個工廠生產的所有產品,其中的每個產品都是座落在不同的產品等級結構中的其中一個產品。 <br><span style="display:block;text-align:center;"><img src="https://www.jyt0532.com/public/abstractfactory2.png" width="750" height="650"></img></span><br> ### <font color="#F59F00">**Abstract Factory Pattern**</font> 套用 abstract factory ```java public class CheesePizza extend Pizza { PizzaIngredientFactory pizzaIngredientFactory; public CheesePizza(PizzaIngredientFactory pizzaIngredientFactory) { this.pizzaIngredientFactory = pizzaIngredientFactory; } void prepare() { dough = pizzaIngredientFactory.createDough(); sauce = pizzaIngredientFactory.createSauce(); cheese = pizzaIngredientFactory.createCheese(); } } ``` 至於 `PizzaStore` 跟它的子類別,概念和 factory method 一樣,由子類別實作 ```java abstract class PizzaStore { public abstract Pizza createPizza(String type); public Pizza orderPizza(String type) { Pizza pizza = createPizza(type); pizza.prepare(); pizza.cook; return pizza; } } public class NewYorkPizzaStore extends PizzaStore { Pizza createPizza(String type) { Pizza pizza = null; PizzaIngredientFactory pizzaIngredientFactory = new NewYorkPizzaIngredientFactory(); if(type.equals("cheese")) { pizza = new CheesePizza(ingredientFactory); } else if(type.equals("veggie")) { pizza = new VeggiePizza(ingredientFactory); } else if(type.equals("clam")) { pizza = new ClamPizza(ingredientFactory); } else if(type.equals("pepperoni")) { pizza = new PepperoniPizza(ingredientFactory); } return pizza; } } ``` order `pizza` 的方法和工廠方法一樣,對於 client 來說,用法一樣並不知道產品已經變成產品族。 ```java PizzaStore pizzaStore = new NewYorkPizzaStore(); Pizza pizza = pizzaStore.orderPizza("cheese"); ``` * <font color="#92d1ff">**Abstract Factory 的結構**</font> **用一個抽象工廠來定義一個產品族的介面,產品族裡面的每個產品的具體類別由繼承的具體工廠來決定** <br><span style="display:block;text-align:center;"><img src="https://www.jyt0532.com/public/abstractfactory3.png" width="750" height="330"></img></span><br> * <font color="#98c37a">**AbstractFactory : PizzaIngredientFactory**</font> 宣告出各個創造同一產品族產品介面。 * <font color="#98c37a">**ConcreteFactory : NewYorkPizzaIngredientFactory**</font> 實作 AbstractFactory。 * <font color="#98c37a">**AbstractProduct : Dough**</font> 宣告產品等級結構的介面。 * <font color="#98c37a">**ConcreteProduct : ThickCrustDough**</font> 實作 AbstractProduct。 * <font color="#92d1ff">**Pros & Cons**</font> * <font color="#98c37a">**Pros**</font> 跟 factory method 一樣 1. 區隔物件的使用和生成 2. 隱藏了物件的細節 3. 性質類似的產品集中管理,比如 NewYork 的原料,client 只要知道有哪些方法要呼叫就好。 * <font color="#98c37a">**Cons**</font> 缺點非常明顯,當我們想加一個產品族很容易,但是加一個產品時卻非常困難,要所有的子類別工廠跟著變動,這被稱為開閉原則的傾斜性,並不符合 OCP。 * <font color="#92d1ff">**Application**</font> 1. 一個系統和產品的生成/組合,保持獨立。 2. 許多類型的產品可以組成產品族,方便集中管理,而且多一個的產品族。 3. 只公開產品 interface 不想公開實作細節。 ### <font color="#F59F00">**Abstract Factory in Detail**</font> abstractFactory 定義了需要創造的產品族,由 concreteFactory 去實作, 所以通常 abstractFactory 每一個創造 product 的抽象方法這兩個都是叫 **工廠方法**。 <br><span style="display:block;text-align:center;"><img src="https://www.jyt0532.com/public/abstractfactory7.png" width="700" height="380"></img></span><br> 由此圖可以看出來,如果我們用 Abstract Factory Pattern 來實作 `PizzaStore` ,我們只需要實作 2 個工廠 `ChicagoPizzaIngredientFactory` 、 `NewYorkPizzaIngredientFactory`,但如果我們用 Factory Method Pattern,我們需要 8 個工廠。 所以這個方法也就是,你發現工廠方法們循著一個產品族的 pattern , 試著把這個產品族分離出來寫成 Abstract Factory interface , 這也就是 ==**rule #2 : Program to an interface, not an implementation**== 。 * <font color="#92d1ff">**退化成 Factory Method Pattern**</font> <br><span style="display:block;text-align:center;"><img src="https://www.jyt0532.com/public/abstractfactory5.png" width="700" height="380"></img></span><br> 把上圖的 `Dough` 改成 `Pizza` 也就是 Factory Method Pattern,一個工廠只生產一個物件, * <font color="#92d1ff">**退化成 SimpleFactory Pattern**</font> <br><span style="display:block;text-align:center;"><img src="https://www.jyt0532.com/public/abstractfactory9.png" width="700" height="380"></img></span><br> 因為每個配料只要一個實作,所以沒有使用 interface 的必要,把上圖的各種配料改成各種 `Pizza` 就是 SimpleFactory Pattern。
×
Sign in
Email
Password
Forgot password
or
By clicking below, you agree to our
terms of service
.
Sign in via Facebook
Sign in via Twitter
Sign in via GitHub
Sign in via Dropbox
Sign in with Wallet
Wallet (
)
Connect another wallet
New to HackMD?
Sign up