Version: Next

工厂方法 Factory Method

源发问题

希望对不同类型的创建对象拥有共同的使用方式

解决方案

在抽象类中定义用于创建对象的接口,让子类决定实例化哪个类。如类图所示,抽象类Creator定义抽象方法factoryMethod,该方法被具体子类覆盖后创建一个product的具体产品,具体产品对象在CreatorAnOperation方法中被product的声名引用。虽然对产品实例化的过程实在子类中进行的,但在AnOperation中通过product对具体产品的使用都相同

定义:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。

可以看作是简单工厂模式中的StaticSimpleFactory不只一种,而是有好几种不太一样的具体工厂,再它们头上再抽一个抽象工厂(Creator)出来,这样就可以在原本封装实例化的基础上更加发挥多态性的威力,体现一种共同的创建Product(Pizza)的策略或者方法

UML类图

image-20200325002106548

image-20200325104910973

代码

  • 先前简单工厂模式中的PizzaStore类变为了抽象类,由派生的子类延时new对象
public abstract class PizzaStore {
public 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 ChicagoPizzaStore extends PizzaStore {
@Override
public Pizza createPizza(String type) {
Pizza pizza = null;
if ("cheese".equals(type)) {
pizza = new ChicagoStyleCheesePizza();
}else if ("greek".equals(type)) {
pizza = new ChicagoStyleGreekPizza();
}else if ("pepperoni".equals(type)){
pizza = new ChicagoStylePepperoniPizza();
}else if ("clam".equals(type)){
pizza = new ChicagoStyleClamPizza();
}
return pizza;
}
}
public class NYPizzaStore extends PizzaStore {
@Override
public Pizza createPizza(String type) {
Pizza pizza = null;
if ("cheese".equals(type)) {
pizza = new NYStyleCheesePizza();
}else if ("greek".equals(type)) {
pizza = new NYStyleGreekPizza();
}else if ("pepperoni".equals(type)){
pizza = new NYStylePepperoniPizza();
}else if ("clam".equals(type)){
pizza = new NYStyleClamPizza();
}
return pizza;
}
}
  • 这些继承抽象类PizzaStore的具体类中,完成对具体产品(ChicagoxxxPizzaorNYxxxPizza)的创建

    public class NYPizzaStore extends PizzaStore {
    @Override
    public Pizza createPizza(String type) {
    Pizza pizza = null;
    if ("cheese".equals(type)) {
    pizza = new NYStyleCheesePizza();
    }else if ("greek".equals(type)) {
    pizza = new NYStyleGreekPizza();
    }else if ("pepperoni".equals(type)){
    pizza = new NYStylePepperoniPizza();
    }else if ("clam".equals(type)){
    pizza = new NYStyleClamPizza();
    }
    return pizza;
    }
    }
    public class ChicagoPizzaStore extends PizzaStore {
    @Override
    public Pizza createPizza(String type) {
    Pizza pizza = null;
    if ("cheese".equals(type)) {
    pizza = new ChicagoStyleCheesePizza();
    }else if ("greek".equals(type)) {
    pizza = new ChicagoStyleGreekPizza();
    }else if ("pepperoni".equals(type)){
    pizza = new ChicagoStylePepperoniPizza();
    }else if ("clam".equals(type)){
    pizza = new ChicagoStyleClamPizza();
    }
    return pizza;
    }
    }
  • 而具体的产品(各种具体披萨)都派生自抽象产品(抽象类Pizza)

    public class ChicagoStyleGreekPizza extends Pizza {
    @Override
    public void prepare() {
    System.out.println("Chicago style greek pizza preparing...");
    }
    }
  • 客户端使用时,声名抽象的Creator(PizzaStore),实例化时使用具体的ConcreteCreator,调用工厂方法,生产具体产品(XxxPizza)
public class Test {
public static void main(String[] args) {
PizzaStore pizzaStore = new NYPizzaStore();
pizzaStore.orderPizza("cheese");
pizzaStore = new ChicagoPizzaStore();
pizzaStore.orderPizza("cheese");
}
}

优缺点

  • 优点
    • 子类只关心如何实现抽象方法来创建一个具体对象,之后便自动拥有了该对象的扩展功能,即为子类提供一个挂钩以获得对象功能的扩展版本
  • 缺点
    • CreatorProduct下容易产生平行类,即每个具体的Creator子类对应产生一个Product下的具体子类对象