更多最新文章欢迎大家访问我的个人博客:smile::豆腐别馆

在现实生活中社会分工越来越细,越来越专业化。各种产品有专门的工厂生产,彻底告别了自给自足的小农经济时代,这大大缩短了产品的生产周期,提高了生产效率。同样,在软件开发中能否做到软件对象的生产和使用相分离呢?能否在满足“开闭原则”的前提下,客户随意增删或改变对软件相关对象的使用呢?这就是关于工厂系列模式要讨论的问题。   

一、模式的定义

  • 简单工厂模式,因类中使用了静态修饰符又叫静态工厂方法(Static Factory Method)模式。
  • 按目的区分它属于创建型模式,按作用范围区分它又属于类模式。(关于设计模式分类的描述可以看上文设计模式概述
  • 我们把被创建的对象称为“产品”,把创建产品的对象称为“工厂”。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。
  • 简单工厂模式并不属于23种GOF设计模式之一,是工厂模式家族中最简单实用的模式,可以理解为是工厂模式的一个基础形式。

当然所有这些都只是有形招式,是化有形为无形的理论基础,实则我们只需要记住:任何的方法,只要是存在有在方法里控制产生对象的逻辑,都可称之为工厂系列的方法。之所以有这么些个命名,只是有人先行一步,将此些方式细分区别,后人纷纷效仿而已。

二、模式的实现

接着上文我们举个栗子,人都得吃东西才能活着,我们都知道男人都喜欢吃豆腐,emm,别想歪了,也爱吃猪蹄。

- Round 1 原始方法

在以前,我们喜欢什么都需要自己去动手丰衣足食。那就是这样的:

  1. 想吃豆腐当然就得先有豆腐,因此在吃之前,我们得要先创建它:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.doufuplus.patterns.factory.simple;

/**
* 豆腐类
* 转载请注明出处,更多技术文章欢迎大家访问我的个人博客站点:https://www.doufuplus.com
*
* @author 丶doufu
* @date 2019/11/27
*/
public class Doufu {

public void eat() {
System.out.println("软软的豆腐...");
}
}
  1. 同理,我们需要再创建个猪蹄子类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.doufuplus.patterns.factory.simple;

/**
* 猪蹄类
* 转载请注明出处,更多技术文章欢迎大家访问我的个人博客站点:https://www.doufuplus.com
*
* @author 丶doufu
* @date 2019/11/27
*/
public class Trotter {

public void eat() {
System.out.println("大大的猪蹄...");
}
}
  1. 饿着肚子终于做好了豆腐跟猪蹄,这下我们想吃什么就可以吃什么了:在这里插入图片描述

    - Round 2 简单工厂

    就这样过去许久,人们慢慢觉得想吃饭还得先饿着肚子烧菜有点烦,所以就都去点起了外卖,我们首先会去到外卖的食物列表里面找,因为食物有很多,所以我们一般会先搜索到豆腐跟大猪蹄子,接着我们需要告知外卖我们想吃的就是豆腐跟大猪蹄子而不要给我送来辣条(下单)。那么画风就是这样的:

  2. 新建个抽象的食物类(具体吃什么食物由用户自己决定):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    package com.doufuplus.patterns.factory.simple;

    /**
    * 食物类
    * 转载请注明出处,更多技术文章欢迎大家访问我的个人博客站点:https://www.doufuplus.com
    *
    * @author 丶doufu
    * @date 2019/11/27
    */
    public abstract class Food {

    public abstract void eat();
    }
  3. 将原先的豆腐及猪蹄子类都继承自食物类,并重写食物的eart()方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.doufuplus.patterns.factory.simple;

/**
* 豆腐类
* 转载请注明出处,更多技术文章欢迎大家访问我的个人博客站点:https://www.doufuplus.com
*
* @author 丶doufu
* @date 2019/11/27
*/
public class Doufu extends Food{

@Override
public void eat() {
System.out.println("软软的豆腐...");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.doufuplus.patterns.factory.simple;

/**
1. 猪蹄类
2. 转载请注明出处,更多技术文章欢迎大家访问我的个人博客站点:https://www.doufuplus.com
3. * @author 丶doufu
4. @date 2019/11/27
*/
public class Trotter extends Food {

@Override
public void eat() {
System.out.println("大大的猪蹄...");
}
}
  1. 新建食物工厂类,生产什么食物由用户自己决定(传参):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
package com.doufuplus.patterns.factory.simple;

/**
* 食物工厂类
* 转载请注明出处,更多技术文章欢迎大家访问我的个人博客站点:https://www.doufuplus.com
*
* @author 丶doufu
* @date 2019/11/27
*/
public class FoodFactory {

// 豆腐
public static final String TYPE_DOUFU = "DOUFU";

// 猪蹄
public static final String TYPE_TROTTER = "TROTTER";

/**
* 获取食物
*/
public static Food getFood(String type) {
if (TYPE_DOUFU.equals(type)) {
// ...
// 放葱花撒盐
// ...
return new Doufu();
} else if (TYPE_TROTTER.equals(type)) {
// ...
// 放葱花撒盐
// ...
return new Trotter();
}
System.out.println("亲,没有这样的食物呢...");
return null;
}
}
  1. 该弄的都弄完了,外卖也送到了,这下可以开吃了:在这里插入图片描述

    - Round 3 多方法工厂

    这里除了上面的传参方式,其实还有另一种。当用户都不想输入豆腐跟猪蹄来找食物了,有这种无理要求的时候,那么只要用户知道该找哪家店可以生产豆腐,哪家店可以生产猪蹄就可以了。即将我们的食物工厂类修改如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    package com.doufuplus.patterns.factory.simple;

    /**
    * 食物工厂类
    * 转载请注明出处,更多技术文章欢迎大家访问我的个人博客站点:https://www.doufuplus.com
    *
    * @author 丶doufu
    * @date 2019/11/27
    */
    public class FoodFactory {

    // 豆腐
    public static final String TYPE_DOUFU = "DOUFU";

    // 猪蹄
    public static final String TYPE_TROTTER = "TROTTER";

    /**
    * 获取食物
    */
    public static Food getFood(String type) {
    if (TYPE_DOUFU.equals(type)) {
    // ...
    // 放葱花撒盐
    // ...
    return new Doufu();
    } else if (TYPE_TROTTER.equals(type)) {
    // ...
    // 放葱花撒盐
    // ...
    return new Trotter();
    }
    System.out.println("亲,没有这样的食物呢...");
    return null;
    }

    // 多方法工厂
    /**
    * 获取豆腐
    */
    public static Food getDoufu() { return new Doufu(); }

    /**
    * 获取猪蹄
    */
    public static Food getTrotter() { return new Trotter(); }
    }

三、模式的优缺点

1. 优点
我们先来回顾下上面的操作,这里最大的一个区别是我们从一开始的要自己动手做豆腐做猪蹄子(自己创建对象),改成了由外卖商家(工厂)帮我们做豆腐做猪蹄子(工厂帮我们创建了对象)。至于豆腐、大猪蹄子的制作过程,如撒葱花撒盐等(对象的创建过程),我们根本不需要参与,只是跟商家说一下(传参/调用方法)商家就帮我们统一处理好了。

2. 缺点
我们知道,人们总避免不了喜新厌旧,豆腐跟猪蹄总有吃腻的一天,当吃腻了的时候人们就总渴望拥有更多品种的食物。随着食物种类的慢慢增加,我们的食物工厂类将会变成何种境地呢?毫无疑问,方法工厂将开始变得臃肿,且每新增一个品种都需要修改原先的工厂类代码。显然,这已经违反了我们单一职责原则及开闭原则。

四、模式的应用场景

知道了它的模式以及优缺点,这下我们就知道了简单工厂模式它的应用场景了:

  • 当需要创建的产品不多,只要一个工厂类就可以完成的时候。
  • 当希望有统一对象处理,不需要使用者关心对象的创建过程的时候。