HeadFirst设计模式4-工厂模式

1.为啥需要工厂模式(why)

在我平常的工作中我们往往会写下如下的代码。

public Pizza orderPizza(String type) {
        Pizza pizza = new Pizza();
        //以下是变化的部分
        if (type.equals("chesss")) {
            pizza = new ChessPizza();
        } else if (type.equals("clam")) {
            pizza = new CalmPizza();
        }
        pizza.bake();
        return pizza;
    }

以上代码的问题在于我们要增加种类的时候,需要打开这段代码进行修改。这样造成系统难以维护,也更容易犯错。

我们对拓展开放,对修改关闭。通常这种情况下,应该抽象出变化的部分。

2.如何实现工厂模式。

  1. 我们首先实现一个简单工厂模式
  • 抽象出变化的部分,就是工厂
public class SimplePIizzaFactory {
    public Pizza createPizza(String type) {
        Pizza pizza = null;
        if (type.equals("ChessPizza")) {
            pizza = new ChessPizza();
        } else if (type.equals("CalmPizza")) {
            pizza = new CalmPizza();
        }
        return pizza;
    }
}
  • 调用的时候只需要用简单工厂生成就行
public class PizzaStroe {
    SimplePIizzaFactory simplePIizzaFactory;

    public PizzaStroe(SimplePIizzaFactory simplePIizzaFactory) {
        this.simplePIizzaFactory = simplePIizzaFactory;
    }

    public Pizza orderPizza(String type) {
        Pizza pizza =simplePIizzaFactory.createPizza(type);
        pizza.bake();
        return pizza;
    }
}

上面这样做的好处在于抽象出变化的部分,供其他部分调用 。另外,当我们需要修改的时候,只需要修改工厂类,其他的部分就不需要变动。

  1. 工厂模式(真正意义上的工厂模式)

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

  • 定义一个基本的工厂基类和它的子工厂类
//定义抽象的Pizza类
public abstract class Pizza {

    public String name;

    public ArrayList ingredent=new ArrayList<>();

    void prepare(){
        System.out.println("Prepare: "+name);
        for(int i=0;i getIngredent() {
        return ingredent;
    }

    public void setIngredent(ArrayList ingredent) {
        this.ingredent = ingredent;
    }
}
public abstract class PizzaStroe {

    public Pizza orderPizza(String type) {
        //不用管子类是什么
        Pizza pizza = createPizza(type);
        pizza.bake();
        return pizza;
    }

    //定义抽象方法,由子类来实现
    public abstract Pizza createPizza(String type);
}
//武汉的工厂类,生产出武汉style的Pizza
public class WuhanPizzaStore extends PizzaStroe {
    @Override
    public Pizza createPizza(String type) {
        Pizza pizza = null;
        if (type.equals("CalmPizza")) {
            pizza = new CalmPizza();
            pizza.ingredent.add("WuhanStyle");
        } else if (type.equals("ChessPizza")) {
            pizza = new ChessPizza();
            pizza.ingredent.add("WuhanStyle");
        }
        return pizza;
    }
}
//北京的工厂类,生产出北京style的Pizza
public class BeijingPizzaStore extends PizzaStroe {
    @Override
    public Pizza createPizza(String type) {
        Pizza pizza = null;
        if (type.equals("CalmPizza")) {
            pizza = new CalmPizza();
            pizza.ingredent.add("BeijingStyle");
        } else if (type.equals("ChessPizza")) {
            pizza = new ChessPizza();
            pizza.ingredent.add("BeijingStyle");
        }
        return pizza;
    }
}
  • 当我们需要Pizza的时候,只需要用那个工厂类就可以构造出那种风格的Pizza
public class PizzaTest {
    public static void main(String[] args) {
        PizzaStroe beijingPizzaStore=new BeijingPizzaStore();
        PizzaStroe wuhanPizzaStore=new WuhanPizzaStore();
        Pizza pizza1=beijingPizzaStore.orderPizza("CalmPizza");
        Pizza pizza2=wuhanPizzaStore.orderPizza("CalmPizza");
        System.out.println(pizza1.getName());
        System.out.println(pizza2.getName());

    }
}

来看下类图的关系

HeadFirst设计模式4-工厂模式_第1张图片
factorypattern.png

  简单工厂与工厂方法的区别:简单工厂把全部的事情在一个地方都处理完了,然而工厂方法却是创建一个框架,让子类决定如何实现。
简单工厂的做法,可以将对象的创建封装起来,但是简单工厂不具备工厂方法的弹性,因为简单工厂不能变更正在创建的产品。

  1. 抽象工厂模式
    首先给出定义

抽象工厂模式 提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类

  • 首先我们定义抽象接口
public interface PropertyFactory {
    public String getName();
    public ArrayList getIngredent();
}

在实际的场合中,抽象接口里面的抽象方法都是返回某个想要创建的抽象类,我这里比较简单,直接返回字符串和集合。之所以称为抽象工厂,我们从这里就可以看出来。通过抽象的方法,返回你希望得到的类的基类。

  • 我们构造抽象工厂类的实现类
public class CalmPropertyFactory implements PropertyFactory {

    @Override
    public String getName() {
        return "NewCalmPizza";
    }

    @Override
    public ArrayList getIngredent() {
        ArrayList arrayList=new ArrayList<>();
        arrayList.add("Newcalm");
        return arrayList;
    }
}

public class ChessPropertyFactory implements PropertyFactory {
    @Override
    public String getName() {
        return "NewChessPizza";
    }

    @Override
    public ArrayList getIngredent() {
        ArrayList arrayList = new ArrayList<>();
        arrayList.add("Newchess");
        return arrayList;
    }
}

那么此时的Pizza的子类应该如此构造

public class CalmPizza extends Pizza {
    PropertyFactory propertyFactory;
    public CalmPizza(PropertyFactory propertyFactory) {
        this.propertyFactory=propertyFactory;
        name=propertyFactory.getName();
        ingredent=propertyFactory.getIngredent();
    }
}

直接用对应的原料工厂来构造。
来看下类图。


HeadFirst设计模式4-工厂模式_第2张图片
abstractFactory.png
  1. 个人总结(conclusion)
      通过以上的描述,我们很容易明白工厂模式,也很容易区分简单工厂和工厂模式的区别(即构造类是在一个工厂类里面统一构造,还是通过子类的工厂方法来构造)。但是令人迷惑的是工厂模式与抽象工厂模式有什么区别。区别如下:

抽象工厂的每个方法实际上看起来都像是工厂方法,每个方法都被声明成抽象。而子类的方法来覆盖这些方法来创建某些对象。注意到,这里的子类是想要构造类的成分,就像我上面的写的name和ingredent成员。Pizza的子类只需要依赖依赖这些成分工厂类,例如ChessPropertyFactory ,就能构造出对象。重点突出抽象,是因为它有一个总的抽象接口,实现它的子类负责构造对象的成分,总而构成对象。

你可能感兴趣的:(HeadFirst设计模式4-工厂模式)