天天看点

设计模式入门——工厂模式(工厂方法)

背景:

Pizza店开始允许加盟,在推广SimpleFactory时,你发现加盟店的缺采用了你的工厂创建pizza,但其他部分却开始采用他们自创的流程,烘烤方法有差异,不需要切片,使用其他厂商的盒子。

我们想建立一个框架,把加盟店和创建比萨捆绑在一起又保持一定的弹性。

SimplePizzaFactory代码,制作pizza的代码绑在PizzaStore里,这么做没有弹性(不能在制作Pizza的过程中,加入自己的方法)。

设计:

把createPizza()方法放回到PizzaStore中并设置为抽象方法,然后每个区域风味创建一个PizzaStore的子类。每一个继承PizzaStore的子类都必须实现createPizza()方法,由各个子类决定如何制造Pizza。

实现:

// 定义为抽象类  让每个域类型都继承这个PizzaStore,每个子类格子决定如何制造pizza
public abstract class PizzaStore {
    // 声明为final 防止被子类覆盖 
    public final Pizza orderPizza(String type) {
        Pizza pizza;
        pizza = createPizza(type);
        pizza.prepare();
        pizza.bake();
        pizza.cut();
        pizza.box();
        return pizza;
    }
    // 把工厂对象装提到这个方法中 子类必须实现
    abstract Pizza createPizza(String type); 
}
           
// 由子类实现一个具体的Pizza
public class NYPizzaStore extends PizzaStore {
    Pizza createPizza(String item) {
        if("cheese".equals(item)){
            return new NYStyleCheesePizza();
        } else if("veggie".equals(item)){
            return new NYStyleVeggiePizza();
        } else if("pepperoni".equals(item)){
            return new NYStylePepperoniPizza();
        } else return null;
    }
}
           

例子:

  1.  Joel和Ethan分别实例化一个ChiagoPizzaStore类和NYPizzaStore
  2. 有了各自的PizzaStore后,Joel和Ethan分别调用了orderPizza()方法,并传入喜欢的Pizza类型
  3. orderPizza()方法调用createPizza()创建Pizza,createPizza()会将创建好的Pizza返回,
  4. orderPizza()并不知道真正创建的是哪一类Pizza,它只知道是Pizza,然后将其准备,烘烤,切片,装盒,派送。

总结:

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

PizzaStore类中orderPizza()方法实现了很多事情(准备、烘培、切片、装盒等),但它不知道哪个子类将实际上制作Pizza,这就是解藕(decouple)。

当orderPizza()调用createPizza()时,某个Pizza店子类将负责创建Pizza。但是子类不是实时作出决定,从orderPizza()方法的角度来说,如果选择在NYStylePizzaStore订购Pizza,就由这个子类做决定。所以并非又子类世纪做决定,而是由顾客决定到哪家风味的Pizza店里才决定了Pizza的风味。

工厂方法用来处理对象的创建,并将这样的行为封装在子类中。这个客户程序中关于超类的代码就和子类对象创建代码解藕了。

// 工厂方法是抽象的,所以依赖子类去处理对象的创建
// 工厂方法将客户(也就是超类中的代码,如orderPizza())和实际创建具体产品的代码分隔开来。
abstract Product factoryMethod(String type)
           

简单工厂与工厂方法之间的差异:简单工厂把全部的事情在一个地方全都处理完了,然而工厂方法却是创建了一个框架,让子类决定要如何实现。比如说,orderPizza()方法提供了一般的框架以便创建Pizza,orderPizza()方法依赖工厂方法创建具体类,并制造出实际的Pizza。而简单的工厂的做法是将对象的创建封装起来,它不具备工厂方法的弹性,因为简单工厂不能变更正在创建的产品。

工厂方法的好处:将创建对象的代码集中在一个对象或方法中,可以避免代码中的重复,并且更方便以后的维护。这也意味着客户在实例化对象时,只会依赖于接口,而不是具体类。这让代码更有弹性,可以应对未来的拓展。