前言:按照惯例我以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; } }
经过这一系列的改造咱们引入了新类型的工厂,也就是所谓的抽象工厂,抽象工厂用来创造原料。
利用抽象工厂咱们代码将从实际工厂解耦,这样若是咱们的工厂须要扩展那么咱们则可在子类中进行修改扩展。
工厂方法与抽象工厂的异同优缺点
相同:都是用来建立对象。
不一样:工厂方法使用的是继承,抽象工厂使用的是组合。
优势:工厂方法只负责从具体类型中解耦,抽象工厂适合将一群相关的产品集合起来。
缺点:抽象工厂扩展接口须要修改每一个子类。