“补课”进行时:设计模式(2)——通过一个超级汽车工厂来了解工厂模式

1. 超级汽车工厂

汽车相信大家都不陌生,我们现在最常用的交通工具得益于在奔驰在 1885 年研制的第一辆“三轮车”,就是下面这个家伙:

今天我来试一下使用程序通过汽车工厂来造汽车。

1.1 定义一辆汽车

public interface Car {
    void name();
    void drive();
}

身为一辆汽车,首先要有自己的名字,其次是要能开,有了这两个东西,基本上就能叫一辆汽车了。

1.2 定义一辆特斯拉、一辆奔驰、一辆奥迪

public class Tesla implements Car {
    @Override
    public void name() {
        System.out.println("我是特斯拉!!!");
    }

    @Override
    public void drive() {
        System.out.println("我是特斯拉,速度贼快!!!");
    }
}

public class Benz implements Car {
    @Override
    public void name() {
        System.out.println("我是奔驰!!!");
    }

    @Override
    public void drive() {
        System.out.println("我是奔驰,内饰豪华!!!");
    }
}

public class Audi implements Car {
    @Override
    public void name() {
        System.out.println("我是奥迪!!!");
    }

    @Override
    public void drive() {
        System.out.println("我是奥迪,科技感十足!!!");
    }
}

这里定义了三辆汽车,分别实现了他们的父亲的两个方法。

1.3 定义抽象汽车工厂

身为一个超级汽车工厂,当然是要能造汽车,我们创建汽车的时候,肯定是希望直接告诉工厂,我要造一辆特斯拉还是造一辆奥迪。

如果是使用特斯拉或者是奥迪作为输入参数,那么创建的方法我们就需要分别写 3 个了,在 Java 中,这里可以使用泛型来作为输入参数,控制参数的输入类型。

public abstract class AbstractCarFactory {
    public abstract  <T extends Car> T createCar(Class<T> clazz);
}

这里使用泛型首先定义了泛型 T 是 Car 的子类,限制了 T 的类型,其次是输入参数必须是 Class 类型。

1.4 汽车创建工厂

接下来,我们定义一个实际的汽车创建工厂:

public class CarFactory extends AbstractCarFactory {
    @Override
    public <T extends Car> T createCar(Class<T> clazz) {
        Car car = null;
        try {
            car = (T)Class.forName(clazz.getName()).newInstance();
        } catch (Exception e) {
            System.out.println("汽车生产出错啦,请回炉重造!");
        }
        return (T) car;
    }
}

1.5 开始生产汽车

public class Test {
    public static void main(String[] args) {
        AbstractCarFactory carFactory = new CarFactory();
        System.out.println("-- 第一辆车生产特斯拉 --");
        Car tesla = carFactory.createCar(Tesla.class);
        tesla.name();
        tesla.drive();

        System.out.println("-- 第二辆车生产奔驰 --");
        Car benz = carFactory.createCar(Benz.class);
        benz.name();
        benz.drive();

        System.out.println("-- 第三辆车生产奥迪 --");
        Car audi = carFactory.createCar(Audi.class);
        audi.name();
        audi.drive();
    }
}

生产的结果如下:

-- 第一辆车生产特斯拉 --
我是特斯拉!!!
我是特斯拉,速度贼快!!!
-- 第二辆车生产奔驰 --
我是奔驰!!!
我是奔驰,内饰豪华!!!
-- 第三辆车生产奥迪 --
我是奥迪!!!
我是奥迪,科技感十足!!!

2. 工厂模式

首先是工厂模式的定义:

Define an interface for creating an object,but let subclasses decide whichclass to instantiate.Factory Method lets a class defer instantiation tosubclasses.(定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。)

下面是一个通用类图:

  • Product: 用于定义产品特性,实现对事物最抽象的定义,就像上面定义的 Car 。
  • ConcreteProduct: 具体对产品定义的实现,就上上面定义的特斯拉和奥迪。
  • Creator: 抽象工厂,用于最抽象对 Product 的构造的定义。
  • ConcreteCreator: Creator 的具体实现,具体实现如何创建产品类。

2.1 抽象产品类

public abstract class Product {
    public void method1() {

    }
    public abstract void method2();
}

2.2 具体产品类

public class ConcreteProduct1 extends Product {
    @Override
    public void method2() {

    }
}

public class ConcreteProduct2 extends Product {
    @Override
    public void method2() {

    }
}

具体的产品类可以有多个,都继承于抽象的产品类。

2.3 抽象工厂类

public abstract class Creator {
    public abstract <T extends Product> T createProduct(Class<T> clazz);
}

2.4 具体工厂类

public class ConcreteCreator extends Creator {
    @Override
    public <T extends Product> T createProduct(Class<T> clazz) {
        Product product = null;
        try {
            product = (Product) Class.forName(clazz.getName()).newInstance();
        } catch (Exception e) {
            // 异常处理
        }
        return (T) product;
    }
}

具体如何产生一个产品的对象的实现,是由具体的工厂类进行实现的,具体的工厂类可以有多个,用于实现多条产品线的生产。

2.5 优点

  • 良好的封装性,代码结构清晰。
  • 良好的扩展性。如果我们需要增加产品类,只需要修改具体的工厂类或者扩展一个新的具体工厂类即可。
  • 屏蔽产品类。工厂模式是点型的解耦框架,高层次的模块只需要知道产品的抽象类,其他的实现类都不需要关心。

3. 工厂模式扩展——多个工厂类

前面说工厂模式可以有多个具体工厂,如果项目复杂度足够高,将所有的产品都放在一个工厂类中做初始化有点不够清晰,那么我们可以实现多个工厂类,由每一个工厂类对应不同的业务规则做对应的产品类的初始化操作。

我如果把上面的那个超级汽车工厂改成多工厂类,先画一个类图:

这个代码我就不写了,和上面的差不多,就是从原来的一个工厂生产三种车变成了三个专属工厂生产三种车。