前言:按照慣例我以Head First設計模式的工廠模式例子開始編碼學習。並由簡單工廠,工廠模式,抽象工廠模式依次演變,概括他們的相同與不一樣。編程
話說Head First認爲簡單工廠並非設計模式,而是一種編程習慣,但並不妨礙咱們使用它,接下來咱們對工廠模式一探究竟。設計模式
首先咱們要開一個披薩店,對於業務不復雜的狀況下咱們能夠快速的開發出一個披薩店以及訂購披薩的邏輯框架
public Pizza OrderPizza() { Pizza pizza = new Pizza(); pizza.Prepare(); pizza.Bake(); pizza.Cut(); pizza.Box(); return pizza; } } public class Pizza { //準備 public void Prepare() { } //烘烤 public void Bake() { } //切片 public void Cut() { } //裝盒 public void Box() { } }
若是咱們有更多的披薩種類可能須要將Pizza定義成抽象類 在訂單裏面根據訂購的披薩種類返回不一樣的披薩,咱們對披薩進行抽象並改造Order。ide
public class PizzaStore { public Pizza OrderPizza(string type) { Pizza pizza=null; if (type == "cheese") { pizza = new CheesePizza(); } else if (type == "viggie") { pizza = new VeggiePizza(); } //else if ...... pizza.Prepare(); pizza.Bake(); pizza.Cut(); pizza.Box(); return pizza; } } public abstract class Pizza { //準備 public void Prepare() { } //烘烤 public void Bake() { } //切片 public void Cut() { } //裝盒 public void Box() { } } //奶酪披薩 public class CheesePizza : Pizza { } //素食披薩 public class VeggiePizza : Pizza { }
到這裏咱們可能想到了,若是增長披薩種類或者移除披薩那麼咱們將對披薩店進行修改。學習
設計原則對擴展開放,對修改關閉。咱們須要將建立披薩的變化封裝起來。對此弄出來一個專門建立披薩的「工廠「類。this
並採用靜態,這樣就不須要實例化對象,也遵循了不對實現編程原則。編碼
public class PizzaStore { public Pizza OrderPizza(string type) { Pizza pizza = SimplePizzaFactory.CreatePizza(type); pizza.Prepare(); pizza.Bake(); pizza.Cut(); pizza.Box(); return pizza; } } public static class SimplePizzaFactory { public static Pizza CreatePizza(string type) { Pizza pizza = null; if (type == "cheese") { pizza = new CheesePizza(); } else if (type == "viggie") { pizza = new VeggiePizza(); } return pizza; } }
這樣將建立披薩簡單的封裝起來便是簡單工廠(靜態工廠),簡單工廠也能夠不用靜態類,但簡單工廠並非一種專門的設計模式(有時候可能會混淆,認爲這便是」工廠模式「),更像是咱們平時編程都會作的一種習慣。咱們將改動封裝在一個局部當有變化的時候只須要修改這個工廠類。spa
如今咱們要開更多的披薩店,例如美國風格披薩店(USSytlePizzaStore)、中國風格披薩店(CHNSytlePizzaStore)。設計
咱們能夠採用簡單工廠模式,建立兩個不一樣風格的披薩工廠,而後建立兩個不一樣風格的披薩店,不一樣風格的披薩店使用對應的披薩工廠來獲取。對象
可是咱們此時的變化點是披薩店。咱們但願披薩店的結構或者流程是按照必定規則的,只是不一樣風格的披薩。此時咱們有更好的解決辦法:工廠模式。
接下來咱們看如何實現
public abstract class PizzaStore { public Pizza OrderPizza(string type) { Pizza pizza= CreatePizza(type); pizza.Prepare(); pizza.Bake(); pizza.Cut(); pizza.Box(); return pizza; } public abstract Pizza CreatePizza(string type); } public class USSytlePizzaStore : PizzaStore { public override Pizza CreatePizza(string type) { Pizza pizza = null; if (type == "cheese") { pizza = new USStyleCheesePizza(); } else if (type == "viggie") { pizza = new USStyleVeggiePizza(); } return pizza; } } public class CHNSytlePizzaStore : PizzaStore { public override Pizza CreatePizza(string type) { Pizza pizza = null; if (type == "cheese") { pizza = new CHNStyleCheesePizza(); } else if (type == "viggie") { pizza = new CHNStyleVeggiePizza(); } return pizza; } } //US奶酪披薩 public class USStyleCheesePizza : Pizza { } //US素食披薩 public class USStyleVeggiePizza : Pizza { } //CHN奶酪披薩 public class CHNStyleCheesePizza : Pizza { } //CHN素食披薩 public class CHNStyleVeggiePizza : Pizza { }
由實現咱們能夠看到咱們將PizzaStore修改爲抽象類,不一樣的披薩店繼承抽象類返回本身不一樣風格的披薩。
這樣設計後當增長產品,咱們也只是在具體的子類披薩店中修改其中的披薩建立,不會影響披薩店自己流程和其餘披薩店的實現。
工廠方法模式:定義了一個建立對象的接口,由子類決定要實例化的類是哪個,工廠方法讓類把實例化推遲到子類。
工廠方法與簡單工廠的區別:工廠方法的子類看起來很像簡單工廠。簡單工廠把所有的事情在一個地方處理完成,而工廠方法倒是建立一個框架,讓子類決定如何實現。
不一樣風格的披薩店有不一樣風格的披薩,而這些披薩的不一樣風格是來自不一樣原料形成,因此不一樣風格的披薩變化的部分是材料。
咱們先建造原料和原料工廠,以中國披薩原料工廠爲例
//披薩原料工廠接口 public interface PizzaIngredientFactory { public Veggie CreateVeggie(); public Cheese CreateCheese(); } //具體工廠實現 public class CNHPizzaIngredientFactory : PizzaIngredientFactory { public Cheese CreateCheese() { return new CHNCheese(); } public Veggie CreateVeggie() { return new CHNVeggie(); } } public abstract class Veggie { } public class USVeggie : Veggie { } public class CHNVeggie : Veggie { } public abstract class Cheese { } public class USCheese : Cheese { } public class CHNCheese : Cheese { }
而後重作Pizza
public abstract class Pizza { public String Name; Veggie veggie; Cheese cheese; //準備 public abstract void Prepare(); //烘烤 public void Bake() { } //切片 public void Cut() { } //裝盒 public void Box() { } }
加入了原料的抽象 Veggie 和 Cheese,同時咱們讓Prepare變成抽象方法,讓他的具體子類決定用什麼材製造不一樣風格的披薩。接着咱們重作子類,以CheesePizza爲例
//奶酪披薩 public class CheesePizza : Pizza { PizzaIngredientFactory IngredientFactory; public CheesePizza(PizzaIngredientFactory IngredientFactory) { this.IngredientFactory = IngredientFactory; } public override void Prepare() { IngredientFactory.CreateCheese(); } }
修改中國披薩店
public class CHNSytlePizzaStore : PizzaStore { public override Pizza CreatePizza(string type) { Pizza pizza = null; //建立中國原材料工廠 CNHPizzaIngredientFactory ingredientFactory = new CNHPizzaIngredientFactory(); if (type == "cheese") { pizza = new CheesePizza(ingredientFactory); } else if (type == "viggie") { pizza = new VeggiePizza(ingredientFactory); } return pizza; } }
經過這一系列的改造咱們引入了新類型的工廠,也就是所謂的抽象工廠,抽象工廠用來創造原料。
利用抽象工廠咱們代碼將從實際工廠解耦,這樣若是咱們的工廠須要擴展那麼咱們則可在子類中進行修改擴展。
工廠方法與抽象工廠的異同優缺點
相同:都是用來建立對象。
不一樣:工廠方法使用的是繼承,抽象工廠使用的是組合。
優勢:工廠方法只負責從具體類型中解耦,抽象工廠適合將一羣相關的產品集合起來。
缺點:抽象工廠擴展接口須要修改每一個子類。