一、工厂方法模式的诞生

  在读这篇文章之前,我先推荐大家读《设计模式之简单工厂模式(Simple Factory Pattern)》这篇文档。工厂方法模式是针对简单工厂模式中违反开闭原则的不足,而提出的改进方案。在简单工厂模式中,每增加一个新产品,就要修改工厂类的调度方法, 针对这个问题,工厂方法模式提出,工厂类提取成抽象的类或接口,定义调度规范。每新增一种产品,不仅要提供产品的实现类,还要提供调度这种产品的工厂类。这样,用户在用工厂方法模式时,需要哪个产品,就调用哪个产品的工厂类,即可获得。就不用只通过一个工厂类传参,去获得不同产品了。简单工厂模式改变的是产品参数,工厂方法模式改变的是工厂类型。

二、工厂方法模式的定义

  工厂方法模式,又称工厂模式、多态工厂模式和虚拟构造器模式,通过定义工厂父类负责定义创建对象的公共接口,而子类则负责生成具体的对象。它的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。

  通过第一部分的描述,这些官方的定义概念,是不是很好理解了呢?

二、工厂方法模式的角色

  由上面的描述,我们可以得到工厂方法中,设计到的角色:

  •   产品规范:和简单工厂模式的产品规范作用一样,定义规范;
  •   产品实现:和简单工厂模式的产品实现一样,实现产品规范的方法;
  •   抽象工厂:工厂方法模式新加的角色,用来制定调度产品的规范,供具体工厂类遵循;
  •   工厂实现类:实现抽象工厂的规范,来调度不同的产品;不同的产品有不同的工厂实现来调度;
  •   产品使用者:也就是业务程序员,工厂方法模式的使用,主要是选择不同的工厂实现类,来获取不同的产品;

三、工厂方法模式的实现

首先,还以家具为例,先定义产品规范,如下:


/**
* 产品规范
*/
public interface Furiniture {

public void createFurniture();
}
 

然后,定义产品实现,如下:

/**
* 产品实现类
*/
public class Table implements Furiniture {
@Override
public void createFurniture() {
System.out.println("生产桌子");
}
}
/**
* 产品实现类
*/
public class Chair implements Furiniture {
@Override
public void createFurniture() {
System.out.println("生产椅子");
}
}

下面,我们要定义工厂,在这里,我们工厂也定义工厂抽象规范,让其他具体工厂类进行实现,如下:

/**
* 工厂抽象类,定义调度产品的规范
*/
public abstract class FurnitureFactory {
public abstract void getFurniture();
}

然后定义工厂的实现类,因为现在有Table和Chair两个产品,所以需要两个工厂实现类,如下:

/**
* 桌子产品的工厂类
*/
public class TableFactory extends FurnitureFactory {
@Override
public void getFurniture() {
new Table().createFurniture();
}
}
/**
* 椅子工厂的工厂类
*/
public class ChairFactory extends FurnitureFactory {
@Override
public void getFurniture() {
new Chair().createFurniture();
}
}

调用者使用工厂方法模式,获得产品:

public class FactoryMethodUser {
public static void main(String[] args) {
//对于使用者而言,要选择具体的产品工厂类,进行产品的获得
FurnitureFactory factory=new TableFactory();
factory.getFurniture();
}
}

当我们想增加产品时,如增加Sofa产品,需要增加产品实现类和产品工厂实现类。

四、工厂方法模式的优缺点

  优点:

    1.面向接口编程;

    2.符合了开闭原则;

  缺点:

    添加新产品时,除了增加新产品类外,还要提供与之对应的具体工厂类,系统类的个数将成对增加,在一定程度上增加了系统的复杂度。

五、与简单工厂模式的区别

  工厂方法模式与简单工厂模式的区别主要是两方面:

    1.对于产品提供方来说,不光要提供新的产品实现,还要提供产品的调度工厂实现类,需要提供两套规范的东西;

    2.对于使用工厂模式的人来说,获得产品,不再是通过一个工厂,通过传入不同的产品参数来获得产品,而是直接选择相应的工厂实现类来获得产品即可。即简单工厂是一个工厂输出不同产品,工厂方法模式是不同工厂输出不同产品。

  思考:工厂方法模式中,抽象工厂类,定义了统一规范,那产品是否有必要再定统一接口规范呢?

  有必要。在定义抽象工厂的规范时,我们是要返回统一产品的。如何统一产品呢?就是定义产品规范。如果抽象工厂里不统一产品输出,那调用者调用起来,也就会产生五花八门的产品,这样明显是不合理的。

六、工厂方法模式在JDK中的应用

  我们以Collection集合为例,说明工厂方法模式的应用。

  Collection中用到的工厂方法模式,其实是工厂方法模式的变种,不是标准的工厂方法模式。我们来分析一下。

  首先,找产品规范,是JDK定义的迭代器接口Iterable, 也就是实现产品,要继承Iterable接口,实现iterator()方法。核心代码如下图:

  工厂抽象类:Collection接口,该抽象工厂定义了生产集合的规范。我们使用的ArrayList,HashSet,就是抽象工厂的实现类。

  我们看Collection的源码可以发现,其继承了Iterable接口。也就是说,抽象工厂中,不光有工厂的规范,还有产品的规范。也就是说,在Collection中,将工厂规范和产品规范合二为一了。

  那么我们可以猜想,工厂的实现类,和产品的实现类,也合二为一了。那么进一步推想,工厂类其实就是产品实现类了,那我们还用写调度方法吗,肯定不需要。我们只需要调用产品的方法,即可。

  这样设计,就省去了工厂类调度产品,再通过产品调用产品方法的逻辑。直接通过工厂类,调用产品的方法。

  我们看ArrayList的源码,其实现思路也是按上面的分析来实现的。

  首先,ArrayList中无需写调度方法了,我们直接找其产品方法,iterator()方法。

由源代码可以看出,产品规范实现返回了Itr对象。来实现接口规范。那我们在调用时,直接通过ArrayList对象的iterator()就可以使用该产品了。

Collection实现工厂方法模式比较隐蔽,不容易被人发现。

设计模式之工厂方法模式(Factory Method Pattern)的更多相关文章

  1. 乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pattern)

    原文:乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pa ...

  2. 设计模式-03工厂方法模式(Factory Method Pattern)

    插曲.简单工厂模式(Simple Factory Pattern) 介绍工厂方法模式之前,先来做一个铺垫,了解一下简单工厂模式,它不属于 GoF 的 23 种经典设计模式,它的缺点是增加新产品时会违背 ...

  3. 【设计模式】工厂方法模式 Factory Method Pattern

    在简单工厂模式中产品的创建统一在工厂类的静态工厂方法中创建,体现了面形对象的封装性,客户程序不需要知道产品产生的细节,也体现了面向对象的单一职责原则(SRP),这样在产品很少的情况下使用起来还是很方便 ...

  4. 二十四种设计模式:工厂方法模式(Factory Method Pattern)

    工厂方法模式(Factory Method Pattern) 介绍定义一个用于创建对象的接口,让子类决定将哪一个类实例化.Factory Method使一个类的实例化延迟到其子类. 示例有SqlMes ...

  5. 【UE4 设计模式】工厂方法模式 Factory Method Pattern 及自定义创建资源

    概述 描述 又称为工厂模式,也叫虚拟构造器(Virtual Constructor)模式,或者多态工厂(Polymorphic Factory)模式 工厂父类负责定义创建产品对象的公共接口,而工厂子类 ...

  6. 设计模式之 - 工厂方法模式 (Factory Method design pattern)

    1. 模式意图:  定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类. 2. 别名(Virtual Constructor) 3. 结构 4. 工厂方法模式C ...

  7. C#设计模式——工厂方法模式(Factory Method Pattern)

    一.概述在软件系统中,经常面临着“某个对象”的创建工作,由于需求的变化,这个对象的具体实现经常面临着剧烈的变化,但是它却拥有比较稳定的接口.如何应对这种变化?如何提供一种封装机制来隔离出“这个易变对象 ...

  8. 六个创建模式之工厂方法模式(Factory Method Pattern)

    问题: 在使用简单工厂模式的时候,如果添加新的产品类,则必需修改工厂类,违反了开闭原则. 定义: 定义一个用于创建对象的接口,让子类决定具体实例化哪个产品类.此时工厂和产品都具有相同的继承结构,抽象产 ...

  9. 工厂方法模式(Factory Method Pattern)

    工厂方法模式概述 工厂方法模式是为了弥补简单工厂模式的不足并且继承它的优点而延生出的一种设计模式,属于GoF中的一种.它能更好的符合开闭原则的要求. 定义:定义了一个用于创建对象的接口,但是让子类决定 ...

随机推荐

  1. Codeforces Round #672 (Div. 2) C1. Pokémon Army (easy version) (DP)

    题意:给你一组数\(a\),构造一个它的子序列\(b\),然后再求\(b_1-b2+b3-b4...\),问构造后的结果最大是多少. 题解:线性DP.我们用\(dp1[i]\)来表示在\(i\)位置, ...

  2. 梨子带你刷burp练兵场(burp Academy) - 服务器篇 - Sql注入 - SQL injection UNION attack, determining the number of columns returned by the query

    目录 SQL injection UNION attack, determining the number of columns returned by the query SQL injection ...

  3. CF1465-D. Grime Zoo

    CF1465-D. Grime Zoo 题意: 一个长度为n,由\(0,1,?\)这三个字符构成的字符串,字符串中\(01\)子串贡献\(x\)值,\(10\)的子串贡献\(y\)值,现在让你把\(? ...

  4. Docker之Dockerfile文件

    Dockerfile是一堆指令,每一条指令构建一层,因此每一条指令的内容就是描述该层应当如何构建,在docker build的时候,按照该指令进行操作,最终生成我们期望的镜像文件 Dockerfile ...

  5. codeforces 1037E-Trips 【构造】

    题目:戳这里 题意:n个点,每天早上会在这n个点中加一条边,每天晚上最大的子图满足子图中每个点都有k条或以上的边. 解题思路:看了官方题解,先把所有的点都连上,再从最后一天往前减边,用set维护最大的 ...

  6. hdu-6237

    A Simple Stone Game Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Ot ...

  7. JVM升华篇

    01 Garbage Collect(垃圾回收) 1.1 如何确定一个对象是垃圾? 要想进行垃圾回收,得先知道什么样的对象是垃圾. 1.1.1 引用计数法 对于某个对象而言,只要应用程序中持有该对象的 ...

  8. Gym 101480I Ice Igloos(思维乱搞)题解

    题意:给个最多500 * 500的平面,有半径最多不为1的n个圆,现在给你1e5条线段,问你每条线段和几个圆相交,时限10s 思路: 因为半径<1,那么我其实搜索的范围只要在线段附近就好了.x1 ...

  9. Doris开发手记1:解决蛋疼的MySQL 8.0连接问题

    笔者作为Apache Doris的开发者,平时感觉相关Doris的文章写的很少.主要是很多时候不知道应该去记录一些怎么样的问题,感觉写的不好就会很慌张.新的一年,希望记录自己在Doris开发过程之中所 ...

  10. canvas画布基本知识点总结

    HTML5的canvas元素使用JavaScript画图: <canvas width="600" height="400"> </canva ...