生活中的工厂模式

1、您需要一辆汽车,可以直接从工厂里面提货,而不用去管这辆汽车是怎么做出来的,以及这个汽车里面的具体实现。

2、玩具店里需要一些坦克玩具,就需要从玩具厂商那边进货,不需要知道这些坦克玩具的制造过程。

工厂方法模式

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

工厂方法模式的类图如下。(下图来自于《Head First 设计模式》)

工厂方法模式

在《Head First 设计模式》中,它举例了在美国不同的城市生产出来的披萨,其每个州的披萨工厂都有着一套的制作步骤被封装起来,比如“准备”、“烘烤”、“切” 和 “包装”。然后每个州的生产的披萨交给具体的工厂类来实现。

这是抽取出 Pizza 共有的属性和制作步骤。

package com.example.demo_springboot.designpattern.factory;

import java.util.ArrayList;
import java.util.List;

public abstract class Pizza {

    String name; // 名称
    String dough; // 面团类型
    String sauce; // 馅料
    List<String> toppings = new ArrayList<>();

    public void prepare() {
        System.out.println("准备:" + name);
        System.out.println("扔面团...");
        System.out.println("添加馅料...");
    }

    public void bake() {
        System.out.println("烤25分钟");
    }

    public void cut() {
        System.out.println("切披萨");
    }

    public void box() {
        System.out.println("包装披萨");
    }

    public String getName() {
        return name;
    }

}

Pizza 的具体实现,芝加哥 Pizza 和 纽约 Pizza。

纽约披萨。

package com.example.demo_springboot.designpattern.factory;

public class NewYorkStyleCheesePizza extends Pizza {

    public NewYorkStyleCheesePizza() {
        name = "纽约风味的奶酪披萨";
        dough = "薄皮面团";
        sauce = "大蒜番茄酱";

        toppings.add("磨碎的雷吉亚诺奶酪");
    }

}

芝加哥披萨。

package com.example.demo_springboot.designpattern.factory;

public class ChicagoStyleCheesePizza extends Pizza {

    public ChicagoStyleCheesePizza() {
        name = "芝加哥风味深盘奶酪披萨";
        dough = "Extra Thick Crust Dough";
        sauce = "Plum Tomato Sauce";
    }

    @Override
    public void cut() {
        System.out.println("切成正方形");
    }

}

然后这些披萨需要交给各个城市的工厂,每个州的披萨工厂都有着一套的制作步骤,所以将步骤封装到抽象类当中。

package com.example.demo_springboot.designpattern.factory;

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 pizza);

}

芝加哥的披萨工厂(注意:类的实例化推迟到子类了)。

public class ChicagoPizzaStore extends PizzaStore {

    @Override
    protected Pizza createPizza(String pizza) {
        if("cheese".equals(pizza)) {
            return new ChicagoStyleCheesePizza();
        }
        return null;
    }

}

纽约的披萨工厂(注意:类的实例化推迟到子类了)。

package com.example.demo_springboot.designpattern.factory;

public class NewYorkPizzaStore extends PizzaStore {

    @Override
    public Pizza createPizza(String pizza) {
        if("cheese".equals(pizza)) {
            return new NewYorkStyleCheesePizza();
        }
        return null;
    }

}

接下来,在不同城市生产不同的披萨。

package com.example.demo_springboot.designpattern.factory;

public class PizzaTest {

    public static void main(String[] args) {
        PizzaStore pizzaStore = new NewYorkPizzaStore();
        Pizza pizza = pizzaStore.orderPizza("cheese");
        System.out.println("A 订购了一个:" + pizza.getName() + "\n");

        pizzaStore = new ChicagoPizzaStore();
        pizza = pizzaStore.orderPizza("cheese");
        System.out.println("B 订购了一个:" + pizza.getName() + "\n");
    }

}

运行一下:

准备:纽约风味的奶酪披萨
扔面团...
添加馅料...
烤25分钟
切披萨
包装披萨
A 订购了一个:纽约风味的奶酪披萨

准备:芝加哥风味深盘奶酪披萨
扔面团...
添加馅料...
烤25分钟
切成正方形
包装披萨
B 订购了一个:芝加哥风味深盘奶酪披萨

抽象工厂模式

抽象工厂模式提供了提供一个创建一系列相关(创建多个与之相关的)或者相互依赖对象的接口,而无需指定他们具体的类。

比如:去公司面试或者上班,肯定有两套或多套衣服吧,比如说有商务装(成套,一系列具体产品)、时尚装(成套,一系列具体产品),甚至对于一个家庭来说,可能有商务女装、商务男装、时尚女装、时尚男装,这些也都是成套的,即一系列具体产品。假设一种情况,在您的家中,某一个衣柜(具体工厂)只能存放某一种这样的衣服(成套,一系列具体产品),每次拿这种成套的衣服时也自然要从这个衣柜中取出了。

抽象工厂模式的类图如下所示。

抽象工厂模式

站外例子

以下,是在菜鸟教程的一个很好的例子:

工厂模式

工厂模式也就是鼠标工厂是个父类,有生产鼠标这个接口。

戴尔鼠标工厂,惠普鼠标工厂继承它,可以分别生产戴尔鼠标,惠普鼠标。

生产哪种鼠标不再由参数决定,而是创建鼠标工厂时,由戴尔鼠标工厂创建。

后续直接调用**鼠标工厂.生产鼠标()**即可

img

抽象工厂模式

抽象工厂模式也就是不仅生产鼠标,同时生产键盘。

也就是 PC 厂商是个父类,有生产鼠标,生产键盘两个接口。

戴尔工厂,惠普工厂继承它,可以分别生产戴尔鼠标+戴尔键盘,和惠普鼠标+惠普键盘。

创建工厂时,由戴尔工厂创建。

后续**工厂.生产鼠标()则生产戴尔鼠标,工厂.生产键盘()**则生产戴尔键盘。

img

在抽象工厂模式中,假设我们需要增加一个工厂

假设我们增加华硕工厂,则我们需要增加华硕工厂,和戴尔工厂一样,继承 PC 厂商。

之后创建华硕鼠标,继承鼠标类。创建华硕键盘,继承键盘类即可。

img

在抽象工厂模式中,假设我们需要增加一个产品

假设我们增加耳麦这个产品,则首先我们需要增加耳麦这个父类,再加上戴尔耳麦,惠普耳麦这两个子类。

之后在PC厂商这个父类中,增加生产耳麦的接口。最后在戴尔工厂,惠普工厂这两个类中,分别实现生产戴尔耳麦,惠普耳麦的功能。 以上。

img