设计模式之工厂方法模式(Factory Method Pattern)
一、工厂方法模式的诞生
在读这篇文章之前,我先推荐大家读《设计模式之简单工厂模式(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)的更多相关文章
- 乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pattern)
原文:乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 工厂方法模式(Factory Method Pa ...
- 设计模式-03工厂方法模式(Factory Method Pattern)
插曲.简单工厂模式(Simple Factory Pattern) 介绍工厂方法模式之前,先来做一个铺垫,了解一下简单工厂模式,它不属于 GoF 的 23 种经典设计模式,它的缺点是增加新产品时会违背 ...
- 【设计模式】工厂方法模式 Factory Method Pattern
在简单工厂模式中产品的创建统一在工厂类的静态工厂方法中创建,体现了面形对象的封装性,客户程序不需要知道产品产生的细节,也体现了面向对象的单一职责原则(SRP),这样在产品很少的情况下使用起来还是很方便 ...
- 二十四种设计模式:工厂方法模式(Factory Method Pattern)
工厂方法模式(Factory Method Pattern) 介绍定义一个用于创建对象的接口,让子类决定将哪一个类实例化.Factory Method使一个类的实例化延迟到其子类. 示例有SqlMes ...
- 【UE4 设计模式】工厂方法模式 Factory Method Pattern 及自定义创建资源
概述 描述 又称为工厂模式,也叫虚拟构造器(Virtual Constructor)模式,或者多态工厂(Polymorphic Factory)模式 工厂父类负责定义创建产品对象的公共接口,而工厂子类 ...
- 设计模式之 - 工厂方法模式 (Factory Method design pattern)
1. 模式意图: 定义一个用于创建对象的接口,让子类决定实例化哪一个类,工厂方法使一个类的实例化延迟到其子类. 2. 别名(Virtual Constructor) 3. 结构 4. 工厂方法模式C ...
- C#设计模式——工厂方法模式(Factory Method Pattern)
一.概述在软件系统中,经常面临着“某个对象”的创建工作,由于需求的变化,这个对象的具体实现经常面临着剧烈的变化,但是它却拥有比较稳定的接口.如何应对这种变化?如何提供一种封装机制来隔离出“这个易变对象 ...
- 六个创建模式之工厂方法模式(Factory Method Pattern)
问题: 在使用简单工厂模式的时候,如果添加新的产品类,则必需修改工厂类,违反了开闭原则. 定义: 定义一个用于创建对象的接口,让子类决定具体实例化哪个产品类.此时工厂和产品都具有相同的继承结构,抽象产 ...
- 工厂方法模式(Factory Method Pattern)
工厂方法模式概述 工厂方法模式是为了弥补简单工厂模式的不足并且继承它的优点而延生出的一种设计模式,属于GoF中的一种.它能更好的符合开闭原则的要求. 定义:定义了一个用于创建对象的接口,但是让子类决定 ...
随机推荐
- java——字符串常量池、字符串函数以及static关键字的使用、数组的一些操作函数、math函数
字符串常量池: 字符串比较函数: 字符串常用方法: 字符串截取函数: 字符串截取函数: static关键字使用: 要调用类中的static类型的变量的时候,可以用"类名.变量名&quo ...
- Codeforces Round #658 (Div. 2) D. Unmerge (思维,01背包)
题意:有两个数组\(a\)和\(b\),每次比较它们最左端的元素,取小的加入新的数组\(c\),若\(a\)或\(b\)其中一个为空,则将另一个全部加入\(c\),现在给你一个长度为\(2n\)的数组 ...
- C# 静态类 单例模式 对比
公司的类都需要使用单例模式实现,这个可以节省资源,避免重复对象的生成.但是静态类也可以做到这一点,而且写起来更简洁,于是查阅相关资料,希望弄明白两者的差别. 1.单例模式可以在用到的时候初始化,而静态 ...
- 一些CTF题目--20/9/3
1. 看源码 POST方法.Extract覆盖. 直接url ?参数不行,因为POST参数不在URL上,GET参数才在 Burpsuite抓包,改成 pass=1&thepassword_1 ...
- codeforces 1042D - Petya and Array【树状数组+离散化】
题目:戳这里 题意:有n个数,问有多少个区间满足[L,R]内的和小于t. 解题思路: [L,R]内的和小于t等价于sum[R]-sum[L-1]<t,将sum[L-1]左移,可以看出R与L的关系 ...
- 操作系统 part4
1.操作系统的启动 CPU加电后,执行BIOS(基本IO处理系统).BIOS会进行硬件的自检和初始化,然后把加载程序(BootLoader)从磁盘上的引导扇区中加载到指定位置0x7c00.然后控制权交 ...
- js code review
js code review https://codereview.stackexchange.com/ refs xgqfrms 2012-2020 www.cnblogs.com 发布文章使用:只 ...
- webpack & chunkhash
webpack & chunkhash https://webpack.js.org/configuration/output/#outputchunkfilename https://web ...
- py django
创建项目 $ django-admin startproject server 运行项目 $ cd server $ python manage.py runserver 创建一个模块 $ pytho ...
- perl 打印简单的help文档
更多 PrintHelp.pm #!/usr/bin/perl package PrintHelp; require Exporter; use v5.26; use strict; use utf8 ...