一、 简介
工厂方法模式是一种 创建模式,该模式使用工厂方法来处理创建对象的问题,而不必指定将要创建的对象的确切类。这是通过调用工厂方法(而不是通过构造函数)来创建对象的,该工厂方法是在接口中指定并由子类实现,或者在基类中实现,并且可以选择由派生类覆盖。
二、工作模式的N种方式
我们从一个简单的披萨项目入手,项目需要满足三个需求:
a、披萨的种类很多(比如 GreekPizz、CheesePizz 等) b、披萨的制作有 prepare,bake, cut, box c、完成披萨店订购功能
1、原始方法
类图
案例
1、定义一个抽象类,完成披萨的制作过程
package com.ycdhz.design.factory.simplefactory; public abstract class Pizza { private String pizzaType; public abstract void prepare(); public void bake() { System.out.println("bake"); } public void cut() { System.out.println("cut"); } public void box() { System.out.println("box"); } public void setPizzaType(String pizzaType) { this.pizzaType = pizzaType; } }
2、不同的Pizza 类型去继承Pizza 的抽象类
package com.ycdhz.design.factory.simplefactory; public class CheesePizza extends Pizza { @Override public void prepare() { System.out.println("制作奶酪披萨的原材料"); } } public class ChickenPizza extends Pizza { @Override public void prepare() { System.out.println("制作鸡肉披萨的原材料"); } }
3、定制一个类,来专门的定制Pizza
package com.ycdhz.design.factory.simplefactory; public class OrderPizza { public void getOrderPizza(String type){ Pizza pizza = null; if(type.equals("cheese")){ pizza = new CheesePizza(); pizza.setPizzaType(type); } else if (type.equals("chicken")){ pizza = new ChickenPizza(); pizza.setPizzaType(type); } else { System.out.println(type + "以售尽"); } pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } }
4、 模拟一个客户端,例如 开一个新的Pizza 店,调用OrderPizza
package com.ycdhz.design.factory.simplefactory; public class PizzaStore { public static void main(String[] args) { OrderPizza orderPizza = new OrderPizza(); orderPizza.getOrderPizza("cheese"); } }
2、简单工厂
每一个Pizza 店铺,都可能有一个对应的OrderPizza 类,如果说我们更新了Pizza 的类型,必然会对所有的OrderPizza 类进行一个修改。 我们可以把创建 Pizza 对象封装到一个类中,这样我们有新的 Pizza 种类时只需要修改该类就可,其它有创建到 Pizza 对象的代码就不需要修改了。
类图
案例
1、 从OrderPizza 中将createPizza 提取出来,形成SimplePizzaFactory
package com.ycdhz.design.factory.simplefactory; public class SimplePizzaFactory { public Pizza createPizza(String type){ Pizza pizza = null; if(type.equals("cheese")){ pizza = new CheesePizza(); } else if (type.equals("chicken")) { pizza = new ChickenPizza(); } else { return pizza; } return pizza; } }
2、 定制Pizza 过程,通过构造方法来实例化 SimplePizzaFactory
package com.ycdhz.design.factory.simplefactory; public class OrderPizza { SimplePizzaFactory simpleFactory; public OrderPizza(SimplePizzaFactory simpleFactory) { this.pizzaType = pizzaType; } public void orderPizza(String type) { Pizza pizza = this.simpleFactory.createPizza(type); if(pizza != null) { pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } else { System.out.println(" 订购披萨失败 "); } } }
3、模拟一个客户端,调用OrderPizza
package com.ycdhz.design.factory.simplefactory; public class PizzaStore { public static void main(String[] args) { OrderPizza pizzaStore = new OrderPizza(new SimplePizzaFactory()); pizzaStore.orderPizza("cheese"); } }
随着用户数量的增加,客户群体也在不断的变换。客户对披萨口味有更多的要求,比如北京的奶酪 pizza、北京的胡椒 pizza 或者是伦敦的奶酪 pizza、伦敦的胡椒 pizza。如果是简单工厂方式,我们可以通过新增ZHSimplePizzaFactory、NYSimplePizzaFactory 来进行解决。但考虑到项目的可维护性,我们可以将项目中实例化功能抽象成抽象方法,放到子类中去完成。
案例
1、 修改OrderPizza 类, 将createPizza 交给子类来完成
public abstract class OrderPizza { public void orderPizza (String type){ Pizza pizza = createPizza(type); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); } public abstract Pizza createPizza(String type); }
2、定义一个ZHOrderPizza 来完成中国口味的pizza 的
public class ZHOrderPizza extends OrderPizza { @Override public Pizza createPizza(String type) { Pizza pizza = null; if(type.equals("cheese")){ pizza = new ZHCheesePizza(); } else if (type.equals("chicken")) { pizza = new ZHChickenPizza(); } else { System.out.println("not pizza"); } return pizza; } }
3、模拟一个客户端,调用OrderPizza
public class PizzaStore { public static void main(String[] args) { OrderPizza pizzaStore = new ZHOrderPizza(); pizzaStore.orderPizza("cheese"); } }
总结:定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类。
4、抽象工厂
随着加盟店铺的增加,我们需要对pizza 的原料进行统一处理。 这个时候我们需要为每个区域建造一个工厂并继承自PizzaIngredientFactory。同时要实现一组原料类供工厂使用。
案例
1、 创建一组原料类
public class Dough {} public class Sauce {}
2、 创建一个原料接口
public interface PizzaIngredientFactory { public Dough createDough(); public Sauce createSauce(); }
package com.ycdhz.design.factory.factorydesign; public class NYPizzaIngredientFactory implements PizzaIngredientFactory { @Override public Dough createDough() { System.out.println("NY pizza Dough"); return null; } @Override public Sauce createSauce() { System.out.println("NY pizza Sauce"); return null; } }
4、 创建一个Pizza 类
public abstract class Pizza { public Dough dough; public Sauce sauce; protected abstract void prepare(); public void bake() { System.out.println("bake"); } public void cut() { System.out.println("cut"); } public void box() { System.out.println("box"); } public Dough getDough() { return dough; } public void setDough(Dough dough) { this.dough = dough; } public Sauce getSauce() { return sauce; } public void setSauce(Sauce sauce) { this.sauce = sauce; } }
5、根据不同种类的Pizza 去继承Pizza 类
public class CheesePizza extends Pizza { PizzaIngredientFactory ingredientFactory; public CheesePizza(PizzaIngredientFactory ingredientFactory){ this.ingredientFactory = ingredientFactory; } @Override public void prepare() { this.dough = ingredientFactory.createDough(); this.sauce = ingredientFactory.createSauce(); } }
6、 通过OrderPizza 进行组装
public abstract class OrderPizza { protected Pizza orderPizza(String type){ Pizza pizza = createPizza(type); pizza.prepare(); pizza.bake(); pizza.cut(); pizza.box(); return pizza; } protected abstract Pizza createPizza(String type); }
public class NYOrderPizza extends OrderPizza { @Override protected Pizza createPizza(String type) { Pizza pizza = null; PizzaIngredientFactory factory = new NYPizzaIngredientFactory(); if(type.equals("cheese")){ pizza = new CheesePizza(factory); } else if (type.equals("chicken")) { pizza = new ChickenPizza(factory); } else { System.out.println("没有当前品种的pizza"); return null; } return pizza; } }
4、模拟一个客户端,调用OrderPizza
public class PizzaStore { public static void main(String[] args) { OrderPizza pizzaStore = new NYOrderPizza(); pizzaStore.orderPizza("cheese"); } }
总结:抽象工厂模式:定义了一个 interface 用于创建相关或有依赖关系的对象簇,而无需指明具体的类。从设计层面看,抽象工厂模式就是对简单工厂模式的改进(或者称为进一步的抽象)。将工厂抽象成两层,OrderPizza( 抽象工厂) 和 具体实现的工厂子类。程序员可以根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂类变成了工厂簇,更利于代码的维护和扩展。