Head First 设计模式(三)工厂模式
2017-04-02 22:47
477 查看
工厂模式可以分为三种:
简单工厂模式、工厂方法模式、抽象工厂模式。
以披萨店“订披萨”为例,每个客人到披萨店订不同的披萨,需要生产出不同的披萨来满足客人的要求。
披萨类:
没有工厂类之前,披萨店订披萨:
缺点:披萨种类每次更改,所有的披萨店(假设还有
找出应用中可能需要变化之处,把他们独立出来。
将创建披萨的部分代码独立出来,成为工厂:
工厂类之后,披萨店订披萨:
简单工厂适用于产品不复杂的情况下,为了方便,还可以将获取产品的方法设置为静态(静态工厂),但这样不能通过继承来改变创建产品的行为。
这样简单工厂制作产品的代码就得改成:
每当有新的产品出现,都得修改工厂类的方法。随着产品的增加,这个方法会越来越庞大和不好维护;另外,这也违反了我们之前学到的一个设计原则:
类应该对扩展开发,对修改关闭
如何改变?这里推出工厂方法模式
用我的理解翻译就是:
根据产品的类别的不同,定义出不同的产品创造工厂方法。需要创造产品的地方引用这些方法。
我们将工厂类创造披萨的方法放在披萨店中作为“工厂方法”来实现(可以将此时的披萨店看成一个制作产品的工厂)。
首先,所有的披萨店都有自己创造披萨的“工厂方法”,所以我们定义一个抽象父类,里面定义了创造披萨的方法,但没有实现过程:
再定义生成不同风味披萨,处在不同地区的披萨店:
工厂方法模式的框架如下:
披萨店就是
当产品进一步增多,且互相之间开始有关联时,我们就需要用抽象工厂模式了。
我们先定义一个披萨抽象类,把披萨需要的所有原料(假设有四种)都“放进去”
现在我们改变思维,制作一个不同的披萨需要不同的原料,所以我们定义一个披萨原理工厂接口:
不同风味的披萨实际就是不同原料的披萨,所以我们定义不同的披萨原料工厂:
接着我们以芝士披萨为例,假设它需要三种原料:面团(dough)、酱料(sauce)、和芝士(cheese),那么不同风味的芝士披萨由不同的芝士原料工厂提供原料,我们只需要指定不同的工厂,则制作出不同风味的芝士披萨
最后我们看一下,现在纽约披萨店制作出披萨的方法
抽象工厂的框架如下:
工厂方法模式通过基础实现,抽象工厂模式通过对象的组合
对于扩展(如新增加一个产品),工厂方法模式可以通过增加一种新继承的工厂类实现;而抽象工厂模式不得不修改接口代码,由此带来大量子类的更改……
简单工厂模式、工厂方法模式、抽象工厂模式。
简单工厂模式
简单工厂其实不是一个设计模式,反而比较像是一种编程习惯。由于经常被使用,所以被许多开发人员误认为是“工厂模式”。以披萨店“订披萨”为例,每个客人到披萨店订不同的披萨,需要生产出不同的披萨来满足客人的要求。
披萨类:
public interface Pizza { /**烘烤*/ public void bake(); /**切片*/ public void cut(); /**打包*/ public void box(); } /** * 奶酪披萨 */ public class CheesePizza implements Pizza{ @Override public void bake() { } @Override public void cut() { } @Override public void box() { } } /** * 榴莲披萨 */ public class DurianPizza implements Pizza{ @Override public void bake() { } @Override public void cut() { } @Override public void box() { } } /** * 蔬菜披萨 */ public class VeggiePizza implements Pizza{ @Override public void bake() { } @Override public void cut() { } @Override public void box() { } }
没有工厂类之前,披萨店订披萨:
/** * 披萨店 */ public class PizzaStore { public Pizza orderPizza(String type) { Pizza pizza = createPizza(type); //披萨的准备 pizza.bake(); pizza.cut(); pizza.box(); return pizza; } public Pizza createPizza(String type){ if("cheese".equals(type)) return new CheesePizza(); else if("veggie".equals(type)){ return new VeggiePizza(); } else if("durian".equals(type)){ return new DurianPizza(); } else { return null; } } }
缺点:披萨种类每次更改,所有的披萨店(假设还有
PizzaStore2、
PizzaStore3类)代码都要改变。所以我们运用之前学到的设计原则:
找出应用中可能需要变化之处,把他们独立出来。
将创建披萨的部分代码独立出来,成为工厂:
/** * 简单工厂模式 */ public class SimpleFactory { public Pizza createPizza(String type){ if("cheese".equals(type)) return new CheesePizza(); else if("veggie".equals(type)){ return new VeggiePizza(); } else if("durian".equals(type)){ return new DurianPizza(); } else { return null; } } }
工厂类之后,披萨店订披萨:
/** * 披萨店 */ publicclass PizzaStore { private SimpleFactory simpleFactory = new SimpleFactory(); public Pizza orderPizza(String type) { //通过工厂获取披萨 Pizza pizza = simpleFactory.createPizza(type); //披萨的准备 pizza.bake(); pizza.cut(); pizza.box(); return pizza; } }
简单工厂适用于产品不复杂的情况下,为了方便,还可以将获取产品的方法设置为静态(静态工厂),但这样不能通过继承来改变创建产品的行为。
工厂方法模式
当产品类别变得复杂,例如披萨又根据生产地的不同而有了不同的口味:纽约风味、芝加哥风味。这样简单工厂制作产品的代码就得改成:
public Pizza createPizza(String local,String type){ //如果店所在地为纽约,则生成纽约风味披萨 if("NY".equals(local)){ if("cheese".equals(type)) return new NYCheesePizza(); else if("veggie".equals(type)){ return new NYVeggiePizza(); } else if("durian".equals(type)){ return new NYDurianPizza(); } else{ return null; } } //如果店所在地为芝加哥,则生成芝加哥风味披萨 else if("Chicago".equals(local)){ if("cheese".equals(type)) return new ChicagoCheesePizza(); else if("veggie".equals(type)){ return new ChicagoVeggiePizza(); } else if("durian".equals(type)){ return new ChicagoDurianPizza(); } else{ return null; } } else { return null; } }
每当有新的产品出现,都得修改工厂类的方法。随着产品的增加,这个方法会越来越庞大和不好维护;另外,这也违反了我们之前学到的一个设计原则:
类应该对扩展开发,对修改关闭
如何改变?这里推出工厂方法模式
定义:
工厂方法模式定义了一个创建对象的接口,但由子类决定要实例的类是哪一个。工厂方法让类把实例化推迟到了子类。用我的理解翻译就是:
根据产品的类别的不同,定义出不同的产品创造工厂方法。需要创造产品的地方引用这些方法。
代码:
仍用披萨来示例,现在披萨店分为了纽约披萨店、芝加哥披萨店,它们各自需要创建各种地区风味的披萨。我们将工厂类创造披萨的方法放在披萨店中作为“工厂方法”来实现(可以将此时的披萨店看成一个制作产品的工厂)。
首先,所有的披萨店都有自己创造披萨的“工厂方法”,所以我们定义一个抽象父类,里面定义了创造披萨的方法,但没有实现过程:
/** * 披萨店 */ public abstract class PizzaStore { public Pizza orderPizza(String type) { //通过工厂方法获取披萨 Pizza pizza = createPizza(type); //披萨的准备 pizza.bake(); pizza.cut(); pizza.box(); return pizza; } /** * 获取披萨的工厂方法 */ abstract Pizza createPizza(String type); }
再定义生成不同风味披萨,处在不同地区的披萨店:
/** * 纽约披萨店 */ public class NYPizzaStore extends PizzaStore{ //返回纽约风味的各种类型披萨 @Override Pizza createPizza(String type) { if("cheese".equals(type)) return new NYCheesePizza(); else if("veggie".equals(type)){ return new NYVeggiePizza(); } else if("durian".equals(type)){ return new NYDurianPizza(); } else { return null; } } } /** * 芝加哥披萨店 */ public class ChicagoPizzaStore extends PizzaStore{ //返回芝加哥风味的各种类型披萨 @Override Pizza createPizza(String type) { if("cheese".equals(type)) return new ChicagoCheesePizza(); else if("veggie".equals(type)){ return new ChicagoVeggiePizza(); } else if("durian".equals(type)){ return new ChicagoDurianPizza(); } else { return null; } } }
工厂方法模式的框架如下:
披萨店就是
Creator,而披萨对应
Product。值得注意的是,网上搜索的工厂方法模式,
Creator对应都是
Factory类,实现同一接口的
Factory子类中实现不同的工厂方法。看上去好像与本书的代码有区别,实际,你把披萨店看成一个
Factory就可以理解了
抽象工厂模式
定义:
抽象工厂模式提供一个接口,用于创建相关或依赖的家族,但不需要明确指定具体类当产品进一步增多,且互相之间开始有关联时,我们就需要用抽象工厂模式了。
代码:
下面继续用披萨举例,让我们把披萨细节化,假设一个芝士披萨需要四个原料做成:面团(dough)、酱料(sauce)、蔬菜(Veggies)、和芝士(cheese):我们先定义一个披萨抽象类,把披萨需要的所有原料(假设有四种)都“放进去”
public abstract class Pizza { /**面团*/ Dough dough; /**酱料*/ Sauce sauce; /**芝士*/ Cheese cheese; /**蔬菜*/ Veggies veggies; /**准备披萨*/ public abstract void prepare(); /**烘烤*/ public abstract void bake(); /**切片*/ public abstract void cut(); /**打包*/ public abstract void box(); }
现在我们改变思维,制作一个不同的披萨需要不同的原料,所以我们定义一个披萨原理工厂接口:
/** * 披萨原料工厂 * @author wangsz */ public interface PizzaIngredientFactory { /** * 制作面团的工厂方法 */ public Dough createDough(); /** * 制作酱油的工厂方法 */ public Sauce createSauce(); /** * 制作芝士的工厂方法 */ public Cheese createCheese(); /** * 制作蔬菜的工厂方法 */ public Veggies createVeggies(); }
不同风味的披萨实际就是不同原料的披萨,所以我们定义不同的披萨原料工厂:
/** * 纽约风味披萨原料工厂 * @author wangsz */ public class ChicagoPizzaIngredientFactory implements PizzaIngredientFactory{ @Override public Dough createDough() { return new ChicagoDough(); } @Override public Sauce createSauce() { return new ChicagoSauce(); } @Override public Cheese createCheese() { return new ChicagoCheese(); } @Override public Veggies createVeggies() { return new ChicagoVeggies(); } }
接着我们以芝士披萨为例,假设它需要三种原料:面团(dough)、酱料(sauce)、和芝士(cheese),那么不同风味的芝士披萨由不同的芝士原料工厂提供原料,我们只需要指定不同的工厂,则制作出不同风味的芝士披萨
/** * 芝士披萨 */ public class CheesePizza extends Pizza { PizzaIngredientFactory pizzaIngredientFactory; public CheesePizza(PizzaIngredientFactory pizzaIngredientFactory) { this.pizzaIngredientFactory = pizzaIngredientFactory; } @Override public void prepare() { this.dough = pizzaIngredientFactory.createDough(); this.sauce = pizzaIngredientFactory.createSauce(); this.cheese = pizzaIngredientFactory.createCheese(); } @Override public void bake() { } @Override public void cut() { } @Override public void box() { } }
最后我们看一下,现在纽约披萨店制作出披萨的方法
//定义原料工厂为纽约披萨原料工厂 PizzaIngredientFactory pizzaIngredientFactory = new NYPizzaIngredientFactory(); //返回纽约风味的各种类型披萨 @Override Pizza createPizza(String type) { if("cheese".equals(type)) return new CheesePizza(pizzaIngredientFactory); else if("veggie".equals(type)){ return new VeggiePizza(pizzaIngredientFactory); } else if("durian".equals(type)){ return new DurianPizza(pizzaIngredientFactory); } else { return null; } }
抽象工厂的框架如下:
抽象工厂和工厂方法模式的区别
工厂方法模式是都是生产一种产品,而抽象工厂是多个相关产品工厂方法模式通过基础实现,抽象工厂模式通过对象的组合
对于扩展(如新增加一个产品),工厂方法模式可以通过增加一种新继承的工厂类实现;而抽象工厂模式不得不修改接口代码,由此带来大量子类的更改……
相关文章推荐
- 【head first 设计模式学习笔记】工厂模式
- Head First 设计模式之工厂模式(Factory Pattern)
- Head First-设计模式:工厂模式
- <Head First 设计模式>:工厂模式1:方法模式--Pizza
- <Head First 设计模式>:工厂模式2:抽象工厂模式--Pizza
- Head First 设计模式学习笔记(4)---工厂模式
- Head First 设计模式之工厂模式(Factory Pattern)
- 《Head First 设计模式》学习笔记:工厂模式
- Head First设计模式之工厂模式
- Head First 设计模式学习——简单工厂方法-工厂方法模式-抽象工厂模式
- 调侃《Head First 设计模式》之工厂模式(二)
- Head First 设计模式(4):工厂模式
- 《Head First 设计模式》之简单工厂
- 学习head first 设计模式之工厂模式
- Head First 设计模式 --工厂模式
- head first 设计模式学习之 简单工厂,工厂方法和抽象工厂
- 《Head First 设计模式》之工厂方法模式
- Head First 设计模式 --4 工厂模式 抽象工厂模式
- Head First 设计模式 —— 工厂模式与工厂方法
- 《Head First 设计模式》之工厂模式