设计模式之工厂模式详解和应用

Posted 赵广陆

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了设计模式之工厂模式详解和应用相关的知识,希望对你有一定的参考价值。

目录


1 工厂模式的历史由来

原始社会自给自足(没有工厂)、农耕社会小作坊(简单工厂,民间酒
坊)、工业革命流水线(工厂方法,自产自销)、现代产业链代工厂(抽象工厂,富士康)

2.简单工厂模式

2.1 简单工厂模式定义

简单工厂模式(Simple Factory Pattern)是指由一个工厂对象决定创建出哪一种产品类的实例,但它不属于GOF 23种设计模式。简单工厂适用于工厂类负责创建的对象较少的场景,且客户端只需要传入工厂类的参数,对于如何创建对象的逻辑不需要关心。·底层工厂承担的太多,创建不同的产品都要经过工厂判断。

2.2 简单工厂模式案例

public class SimpleFactoryTest 
    public static void main(String[] args) 
        CourseFactory factory = new CourseFactory();
        ICourse course = factory.create(JavaCourse.class);
        course.record();
    


public interface ICourse 
    void record();


public class JavaCourse implements ICourse 
    public void record() 
        System.out.println("录制Java课程");
    

public class CourseFactory 
    public ICourse create(Class<? extends ICourse> clazz)
        // 反射
        try 
            if (null != clazz) 
                return clazz.newInstance();
            
        catch (Exception e)
            e.printStackTrace();
        
        return null;
    

这里使用的反射看着代码好一些,如果是一个一个判断就麻烦了。

2.3 简单工厂模式相关源码

  • Calendar.getInstance()
  • LoggerFactory.getLogger()

简单工厂模式在 JDK 源码也是无处不在,现在我们来举个例子,例如 Calendar 类,看Calendar.getInstance()方法,下面打开的是Calendar的具体创建类:

    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
            
        
   

还有一个大家经常使用的 logback,我们可以看到 LoggerFactory 中有多个重载的方法
getLogger():

    public static Logger getLogger(String name) 
        ILoggerFactory iLoggerFactory = getILoggerFactory();
        return iLoggerFactory.getLogger(name);
    
    public static Logger getLogger(Class clazz) 
        return getLogger(clazz.getName());
    

2.4 简单工厂模式优缺点

  • 优点
    • 简单
  • 缺点
    • 工厂类的职责相对过重,不易于扩展过于复杂的产品结构。

3 工厂方法模式

3.1 工厂方法模式定义

工厂方法模式(Factory Method Pattern)是指定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类,工厂方法让类的实例化推迟到子类中进行。在工厂方法模式中用户只需要关心所需产品对应的工厂,无须关心创建细节,而且加入新的产品符合开闭原则。比简单工厂更加细化有了各种工厂,自己去实现对应的工厂。

3.2 工厂方法模式案例

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


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


public interface ICourseFactory 
    ICourse create();

public class JavaCourse implements ICourse 
    public void record() 
        System.out.println("录制Java课程");
    

public interface ICourse 
    void record();


//python同理...

3.3 工厂方法模式源码

再来看看logback中工厂方法模式的应用,看看类图就OK了:

3.4 工厂方法模式优缺点

  • 工厂方法适用于以下场景:
    1. 创建对象需要大量重复的代码。
    2. 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节。
    3. 一个类通过其子类来指定创建哪个对象。
  • 工厂方法也有缺点:
    1. 类的个数容易过多,增加复杂度。
    2. 增加了系统的抽象性和理解难度。

4 抽象工厂模式

4.1 抽象工厂模式定义

抽象工厂模式(AbastractFactory Pattern)是指提供一个创建一系列相关或相互依赖对象的接口,无须指定他们具体的类。客户端(应用层)不依赖于产品类实例如何被创建、实现等细节,强调的是一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复的代码。需要提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。工厂有一些列产品,将这些产品就是类抽象出来。

讲解抽象工厂之前,我们要了解两个概念产品等级结构产品族,看下面的图:

从上图中看出有正方形,圆形和菱形三种图形,相同颜色深浅的就代表同一个产品族,相同形状的代表同一个产品等级结构。同样可以从生活中来举例,比如,美的电器生产多种家用电器。那么上图中,颜色最深的正方形就代表美的洗衣机、颜色最深的圆形代表美的空调、颜色最深的菱形代表美的热水器,颜色最深的一排都属于美的品牌,都是美的电器这个产品族。再看最右侧的菱形,颜色最深的我们指定了代表美的热水器,那么第二排颜色稍微浅一点的菱形,代表海信的热水器。同理,同一产品结构下还有格力热水器,格力空调,格力洗衣机。

再看下面的这张图,最左侧的小房子我们就认为具体的工厂,有美的工厂,有海信工厂,有格力工厂
每个品牌的工厂都生产洗衣机热水器空调

4.2 抽象工厂模式案例

public class AbstractFactoryTest 
    public static void main(String[] args) 
        JavaCourseFactory factory = new JavaCourseFactory();
        factory.createNote().edit();
        factory.createVideo().record();
    

/**
 * 抽象工厂CourseFactory类:
 * 抽象工厂是用户的主入口
 * 在Spring中应用得最为广泛的一种设计模式
 * 易于扩展
 */
public abstract class CourseFactory 
    public void init()
        System.out.println("初始化基础数据");
    
    protected abstract INote createNote();
    protected abstract IVideo createVideo();

/**
 * 创建Java产品族的具体工厂JavaCourseFactory
 */
public class JavaCourseFactory extends CourseFactory 
    public INote createNote() 
        super.init();
        return new JavaNote();
    
    public IVideo createVideo() 
        super.init();
        return new JavaVideo();
    

/**
 * 创建Java产品族,Java视频JavaVideo类:Java视频
 */
public class JavaVideo implements IVideo 
    public void record() 
        System.out.println("录制Java视频");
    

/**
 * 录播视频:IVideo接口
 */
public interface IVideo 
    void record();

/**
 * 扩展产品等级Java课堂笔记JavaNote类:Java笔记
 */
public class JavaNote implements INote 
    public void edit() 
        System.out.println("编写Java笔记");
    

/**
 * 课堂笔记:INote接口
 */
public interface INote 
    void edit();

// 创建Python产品族的具体工厂PythonCourseFactory省略。。。

上面的代码完整地描述了两个产品族Java课程和Python课程,也描述了两个产品等级视频和手记。抽象工厂非常完美清晰地描述这样一层复杂的关系。但是,不知道大家有没有发现,如果我们再继续扩展产品等级,将源码 Source也加入到课程中,那么我们的代码从抽象工厂,到具体工厂要全部调整,很显然不符合开闭原则。

4.3 抽象工厂模式优缺点

抽象工厂缺点

  1. 规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的接口。
  2. 增加了系统的抽象性和理解难度。

5 简单工厂 vs 工厂方法 vs 抽象工厂

简单工厂:产品的工厂
工厂方法:工厂的工厂
抽象工厂:复杂产品的工厂
简单工厂:工厂是一个实体类,内部直接根据逻辑创建对应的产品。
工厂方法:工厂首先有个接口定义规范。不同的产品使用不同的实体类工厂根据规范和需求创建对应的产品。这就是它们的区别。
工厂方法是生产一类产品,抽象工厂是生产一个产品族

以上是关于设计模式之工厂模式详解和应用的主要内容,如果未能解决你的问题,请参考以下文章

设计模式之工厂模式详解(java)

JAVA 设计模式之 工厂模式详解

Java设计模式之创建型:工厂模式详解(简单工厂+工厂方法+抽象工厂)

Java设计模式之简单工厂工厂方法和抽象工厂

Java设计模式之五大创建型模式(附实例和详解)

测开之路十七:设计模式之简单工厂和工厂方法