(一)简单工厂模式

声明:本篇文章除部分引用外,均为原创内容,如有雷同纯属巧合,引用转载请附上原文链接与声明。*
注:本文若包含部分下载内容,本着一站式阅读的想法,本站提供其对应软件的直接下载方式,但是由于带宽原因下载缓慢是必然的,建立读者去相关官网进行下载,若某些软件禁止三方传播,请在主页上通过联系作者的方式将相关项目进行取消。

参考引用

定义

由工厂对象决定创建出哪一种产品的实例

类型

创建型,但是不属于GOF23种设计模式

适用场景
  • 工厂类负责创建的对象比较少
  • 客户端(应用层)
优点

只需要传入一个可选择的正确参数,就可以获取到所需要的对象,而无需知道创建的细节

缺点

工厂类的职责相对过重,强依赖于所需要创建的对象类,如果需要该工程能够创建新的工厂,则需要修改工厂类的代码,违背了开闭原则

Coding

需求:某车辆工厂可以根据客户的需求生产各种类型的车辆,比如小轿车,自行车,大卡车。
根据需求,设计出来如下几个类。

车辆基类

public abstract class Vehicle {

    /**
     * 声明汽车类型
     */
    public abstract void printType();
}

小轿车类

public class Car extends Vehicle {

    @Override
    public void printType() {
        System.out.println("小轿车");
    }
}

自行车类

public class Bicycle extends Vehicle {

    @Override
    public void printType() {
        System.out.println("自行车");
    }
}

大卡车类

public class Truck extends Vehicle {

    @Override
    public void printType() {
        System.out.println("大卡车");
    }
}

车辆工厂类

public class VehicleSimpleFactory {

    /**
     * 根据类型产生指定类型的车辆
     * @param type 车辆类型
     * @return
     */
    public static Vehicle produceVehicle(String type) {
        if (type.equals("小轿车")) {
            return new Car();
        } else if (type.equals("自行车")) {
            return new Bicycle();
        } else if (type.equals("大卡车")) {
            return new Truck();
        }
        throw new IllegalArgumentException("不支持的汽车类型");
    }
}

客户类

public class Client {

    /**
     * 就直接使用main方法作为客户类的消费方法
     * @param args
     */
    public static void main(String[] args) {
        Vehicle vehicle = VehicleSimpleFactory.produceVehicle("bicycle");
        vehicle.printType();
    }
}

全局UML

可以从UML中看到,在简单工厂模式中,客户类是不会直接依赖车辆的各个实现类,其所需要的产品类型的创建过程完全又车辆工厂来进行的实现,客户类获取到所需产品后直接使用即可。

JDK源码解析

本次我们解析JDK的java.util.Calendar类,该类是一个抽象类,其UML如下

其中有一个createCalendar()方法,该方法通过入参来决定创建哪个实现类。

    private static Calendar createCalendar(TimeZone zone,
                                           Locale aLocale) {
        CalendarProvider provider =
                LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale)
                        .getCalendarProvider();
        if (provider != null) {
            try {
                return provider.getInstance(zone, aLocale);
            } catch (IllegalArgumentException iae) {
                // fall back to the default instantiation
            }
        }

        Calendar cal = null;

        if (aLocale.hasExtensions()) {
            String caltype = aLocale.getUnicodeLocaleType("ca");
            if (caltype != null) {
                switch (caltype) {
                    case "buddhist":
                        cal = new BuddhistCalendar(zone, aLocale);
                        break;
                    case "japanese":
                        cal = new JapaneseImperialCalendar(zone, aLocale);
                        break;
                    case "gregory":
                        cal = new GregorianCalendar(zone, aLocale);
                        break;
                }
            }
        }
        if (cal == null) {
            if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") {
                cal = new BuddhistCalendar(zone, aLocale);
            } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja"
                    && aLocale.getCountry() == "JP") {
                cal = new JapaneseImperialCalendar(zone, aLocale);
            } else {
                cal = new GregorianCalendar(zone, aLocale);
            }
        }
        return cal;
    }

在switch语法那里可以明显看到其根据入参来判断实例化哪一个实现类,也就是根据需求对所需要的产品进行初始化。除了以上类,还有很多诸如此类使用简单工厂对产品初始化构建过程进行封装,比如JDBC驱动加载等等。