设计模式之创建型设计模式-工厂方法模式

1. 模式简介

工厂方法模式(Factory Method Pattern):又称为工厂模式,属于创建型设计模式。在工厂方法模式中,工厂父类负责定义创建对象的公共接口,工厂子类负责生成具体的对象,这样做的目的是将具体类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体对象。本文将使用 糖果工厂生产不同口味的糖果 这个实际场景,用代码来实现 工厂方法模式

2. 模式角色

工厂方法模式包含以下4种角色:

  1. 抽象实体(Candy):糖果类基类
  2. 具体实体实现(LemonCandyWatermelonCandy):具体口味糖果实现
  3. 抽象工厂(CandyFactory):糖果工厂类基类
  4. 具体工厂实现(LemonCandyFactoryWatermelonCandyFactory):具体口味糖果工厂类实现

3. UML图例

4. 代码实现

4.1. 步骤一:创建抽象糖果类

Candy.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* <p>
* 糖果抽象类
* </p>
*
* @package: com.xkcoding.design.pattern.creational.factorymethod
* @description: 糖果抽象类
* @author: yangkai.shen
* @date: Created in 2019-02-14 11:28
* @copyright: Copyright (c) 2019
* @version: V1.0
* @modified: yangkai.shen
*/
public abstract class Candy {

/**
* 口味
*/
public abstract void taste();
}

4.2. 步骤二:创建抽象糖果工厂类

CandyFactory.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* <p>
* 糖果工厂抽象类
* </p>
*
* @package: com.xkcoding.design.pattern.creational.factorymethod
* @description: 糖果工厂抽象类
* @author: yangkai.shen
* @date: Created in 2019-02-14 11:29
* @copyright: Copyright (c) 2019
* @version: V1.0
* @modified: yangkai.shen
*/
public abstract class CandyFactory {
/**
* 生产糖果
*
* @return 对应口味的糖果
*/
public abstract Candy produceCandy();
}

4.3. 步骤三:创建具体的不同口味的糖果类

LemonCandy.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* <p>
* 柠檬味糖果
* </p>
*
* @package: com.xkcoding.design.pattern.creational.factorymethod
* @description: 柠檬味糖果
* @author: yangkai.shen
* @date: Created in 2019-02-14 11:28
* @copyright: Copyright (c) 2019
* @version: V1.0
* @modified: yangkai.shen
*/
public class LemonCandy extends Candy {
/**
* 口味
*/
@Override
public void taste() {
System.out.println("柠檬味");
}
}

WatermelonCandy.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* <p>
* 西瓜味糖果
* </p>
*
* @package: com.xkcoding.design.pattern.creational.factorymethod
* @description: 西瓜味糖果
* @author: yangkai.shen
* @date: Created in 2019-02-14 11:28
* @copyright: Copyright (c) 2019
* @version: V1.0
* @modified: yangkai.shen
*/
public class WatermelonCandy extends Candy {
/**
* 口味
*/
@Override
public void taste() {
System.out.println("西瓜味");
}
}

4.4. 步骤四:创建具体的不同口味的糖果工厂类

LemonCandyFactory.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* <p>
* 柠檬味糖果工厂类
* </p>
*
* @package: com.xkcoding.design.pattern.creational.factorymethod
* @description: 柠檬味糖果工厂类
* @author: yangkai.shen
* @date: Created in 2019-02-14 11:30
* @copyright: Copyright (c) 2019
* @version: V1.0
* @modified: yangkai.shen
*/
public class LemonCandyFactory extends CandyFactory {
/**
* 生产柠檬味糖果
*
* @return 柠檬味糖果
*/
@Override
public Candy produceCandy() {
return new LemonCandy();
}
}

WatermelonCandyFactory.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* <p>
* 西瓜味糖果工厂类
* </p>
*
* @package: com.xkcoding.design.pattern.creational.factorymethod
* @description: 西瓜味糖果工厂类
* @author: yangkai.shen
* @date: Created in 2019-02-14 11:30
* @copyright: Copyright (c) 2019
* @version: V1.0
* @modified: yangkai.shen
*/
public class WatermelonCandyFactory extends CandyFactory {
/**
* 生产西瓜味糖果
*
* @return 西瓜味糖果
*/
@Override
public Candy produceCandy() {
return new WatermelonCandy();
}
}

4.5. 步骤五: 测试

PatternTest.java

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
import com.xkcoding.design.pattern.creational.factorymethod.Candy;
import com.xkcoding.design.pattern.creational.factorymethod.CandyFactory;
import com.xkcoding.design.pattern.creational.factorymethod.LemonCandyFactory;
import com.xkcoding.design.pattern.creational.factorymethod.WatermelonCandyFactory;

/**
* <p>
* 工厂方法模式测试类
* </p>
*
* @package: com.xkcoding.design.pattern.creational.factorymethod.run
* @description: 工厂方法模式测试类
* @author: yangkai.shen
* @date: Created in 2019-02-14 14:54
* @copyright: Copyright (c) 2019
* @version: V1.0
* @modified: yangkai.shen
*/
public class PatternTest {
public static void main(String[] args) {
CandyFactory factory1 = new LemonCandyFactory();
Candy candy1 = factory1.produceCandy();
candy1.taste();

CandyFactory factory2 = new WatermelonCandyFactory();
Candy candy2 = factory2.produceCandy();
candy2.taste();
}
}

5. 应用

1
2
// JDK中的应用
// 获取日历对象 -> Calendar.getInstance() -> createCalendar(TimeZone zone,Locale aLocale)

6. 场景

  • 工厂类负责创建的对象比较少:由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
  • 客户端只知道传入工厂类的参数,对于如何创建对象不关心:客户端既不需要关心创建细节,甚至连类名都不需要记住,只需要知道类型所对应的参数。

7. 优缺点

优点: 以本例为例,1、扩展性高,如果想增加一个具体口味的糖果,只需要添加具体口味的糖果实现,同时添加具体口味的糖果工厂即可。2、屏蔽糖果的具体实现,调用方只关心抽象实体的通用接口在具体口味糖果类中的不同实现。

缺点: 以本例为例,每增加一种糖果口味,都需要增加一种具体的实现类,同时增加具体的工厂类,如果系统中存在很多不同口味的糖果,则会导致类的数量成倍增加,增加了系统的复杂度。

8. 完整代码地址

https://github.com/xkcoding/design-pattern/tree/master/src/main/java/com/xkcoding/design/pattern/creational/factorymethod

-------------本文结束  感谢您的阅读-------------
xkcoding wechat
欢迎来我的公众号「xkcoding小凯扣丁」逛逛
o(╯□╰)o 赞助一杯咖啡 ~~