Skip to content

工厂模式

简单工厂模式(产品的工厂)

定义:由一个工厂对象决定创建出哪一种产品类的实例。但他不属于 GOF 23种设计模式之一

理解:不主动地调用经常需要创建的对象的构造方法,而是使用一个工厂来调用其方法帮助我们创建这个需要创建的对象

适用场景:创建对象较少且数量确定的场景

优点:只需传入一个正确的参数或不传入也可以,就可以获取所需对象,无须知道创建细节

缺点:增加新的产品时需要修改工厂类的判断逻辑,违背开闭原则,不易于扩展过于复杂的产品结构

示例

课程的规范

java
public interface ICourse {
    /**
     * 录制视频
     * @return
     */
    void record();
}

Java课程

java
public class JavaCourse implements ICourse {

    public void record() {
        System.out.println("录制Java课程");
    }
}

Python课程

java
public class PythonCourse implements ICourse {

    public void record() {
        System.out.println("录制Python课程");
    }
}

创建课程的工厂

java
public class CourseFactory {
    /**
     * 通过全限定类名来创建对象
     *
     * @param className 全限定类名
     * @return 对象
     */
    public ICourse create(String className) {
        try {
            if (!(null == className || "".equals(className))) {
                return (ICourse) Class.forName(className).newInstance();
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 通过类来创建对象
     *
     * @param clazz
     * @return 对象
     */
    public ICourse create(Class<? extends ICourse> clazz) {
        try {
            if (null != clazz) {
                return clazz.newInstance();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

客户端使用

java
public class SimpleFactoryTest {

    public static void main(String[] args) {

        CourseFactory factory = new CourseFactory();
      	// 通过全限定类名来创建对象
        ICourse course1 = factory.create("com.pattern.factory.JavaCourse");
        course1.record();
				// 通过类来创建对象
        ICourse course2 = factory.create(JavaCourse.class);
        course2.record();

    }
}

简单工厂模式在源码中的体现

JDK

Calendar 类中的 getInstance() 方法具体也是通过一个简单工厂来创建实例

java
public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> {
	// ...
    public static Calendar getInstance() {
        return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
    }
    // ...
    private static Calendar createCalendar(TimeZone zone, Locale aLocale) {
        // ...
        Calendar cal = null;
		// 根据caltype来创建
        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;
                }
            }
        }
        // 通过caltype无法创建,那就用其他条件
        if (cal == null) {
            // If no known calendar type is explicitly specified,
            // perform the traditional way to create a Calendar:
            // create a BuddhistCalendar for th_TH locale,
            // a JapaneseImperialCalendar for ja_JP_JP locale, or
            // a GregorianCalendar for any other locales.
            // NOTE: The language, country and variant strings are interned.
            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;
    }
}

slf4j

slf4j 中的 Logger 日志类就是通过 LoggerFactory 日志工厂创建的

java
public final class LoggerFactory {
    public static Logger getLogger(String name) {
        ILoggerFactory iLoggerFactory = getILoggerFactory();
        return iLoggerFactory.getLogger(name);
    }

    public static Logger getLogger(Class<?> clazz) {
        Logger logger = getLogger(clazz.getName());
        // ...
        return logger;
    }
}

工厂方法模式(工厂的工厂)

定义:定义一个创建对象的工厂接口(定义所有工厂的规范,一般不会用抽象类),让实现这个工厂接口的工厂实现类来决定实例化哪个类。工厂方法模式让类的实例化推迟到工厂实现类中进行

理解:不同的类由不同的工厂来创建,这些工厂都实现了原始的工厂接口。

适用场景:创建对象需要大量重复的代码。客户端不依赖于产品类实例如何被创建、实现等细节。一个类通过其子类来指定创建哪个对象。解决产品扩展的问题(简单工厂模式当新增产品时需要修改工厂类的逻辑,而工厂方法模式只需新增工厂)

优点:用户只需要关系所需产品对应的工厂,无须关心创建细节。且新加入产品符合开闭原则,提高系统的可扩展性(加入新的工厂即可,无须修改原有工厂)

缺点:类的个数容易过多(新增一个产品,需要新加一个类和一个负责创建它的工厂类),增加代码结构复杂度,增加系统的抽象性和理解难度

示例

课程工厂的规范

java
public interface ICourseFactory {

    ICourse create();

}

Java课程工厂

java
public class JavaCourseFactory implements ICourseFactory {
    public ICourse create() {
        return new JavaCourse();
    }
}

Python课程工厂

java
public class PythonCourseFactory implements ICourseFactory {
    public ICourse create() {
        return new PythonCourse();
    }
}

课程的规范

java
public interface ICourse {
    /**
     * 录制视频
     * @return
     */
    void record();
}

Java课程

java
public class JavaCourse implements ICourse {

    public void record() {
        System.out.println("录制Java课程");
    }
}

Python课程

java
public class PythonCourse implements ICourse {

    public void record() {
        System.out.println("录制Python课程");
    }
}

客户端使用

java
public class FactoryMethodTest {
    public static void main(String[] args) {
		// 创建Python课程
        ICourseFactory factory = new PythonCourseFactory();
        ICourse course = factory.create();
        course.record();
		// 创建Java课程
        factory = new JavaCourseFactory();
        course = factory.create();
        course.record();
    }
}

抽象工厂模式(复杂产品的工厂)

定义:提供一个创建一系列相关或相互依赖对象的接口,无须指定他们具体的类

理解:抽象的工厂,创建抽象的对象;具体的工厂继承抽象的工厂,创建的对象实现抽象的对象。相当于定义一个具有标准的产品制作的标准,不同的工厂创建不同的产品。例如:格力公司制作格力冰箱、格力空调;美的公司制作美的冰箱、美的空调 。不光需要实现工厂,也需要实现具体产品

适用场景:客户端不依赖于产品类实例如何被创建、实现的细节。强调一系列属于同一产品族的产品对象一起使用创建对象需要大量重复的代码。提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现

优点:具体产品在应用层代码隔离,无须关心创建细节。将一个系列的产品族统一到一起创建。

缺点:规定了所有的被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的接口。类非常多,增加系统的理解难度

Spring中的抽象工厂AbstractFactory --> AnnotationApplicationContextXmlApplicationContext

示例

抽象工厂

java
public abstract class CourseFactory {

    public void init(){
        System.out.println("初始化基础数据");
    }

    protected abstract INote createNote();

    protected abstract IVideo createVideo();

}

Java课程工厂

java
public class JavaCourseFactory extends CourseFactory {

    public INote createNote() {
        super.init();
        return new JavaNote();
    }

    public IVideo createVideo() {
        super.init();
        return new JavaVideo();
    }
}

Python课程工厂

java
public class PythonCourseFactory extends CourseFactory {

    public INote createNote() {
        super.init();
        return new PythonNote();
    }


    public IVideo createVideo() {
        super.init();
        return new PythonVideo();
    }
}

笔记的规范

java
public interface INote {
    void edit();
}

视频的规范

java
public interface IVideo {
    void record();
}

具体课程的笔记和视频的实现省略,篇幅过长,理解原理即可

工厂方法模式和抽象工厂模式的区别

  • 工厂方法是一个实现标准的具体工厂定义一个实现标准的具体产品;抽象工厂是一个实现标准的具体工厂定义一系列实现标准的具体产品(生态)

  • 抽象工厂的顶层工厂可以是接口,也可以是包含一部分前置后置逻辑的抽象类