设计模式之创建型设计模式-简单工厂模式

1. 模式简介

简单工厂模式(Simple Factory Pattern):它属于创建型设计模式不属于23种设计模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。本文将使用 糖果工厂生产不同口味的糖果 这个实际场景,用代码来实现 简单工厂模式

2. 模式角色

简单工厂包含3个角色:

  1. 工厂角色(CandyFactory):主要负责创建具体的实例。
  2. 抽象实体(Candy):它是工厂角色所创建的所有实例的父类,包含所有具体实例所共有的公共接口。
  3. 具体特征的实体(LemonCandyWatermelonCandy):所有由工厂角色创建出来的实例都属于具体实体。

3. UML图例

3.1. 未使用简单工厂模式的UML图

3.2. 使用简单工厂模式之后的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.simplefactory
* @description: 糖果抽象类
* @author: yangkai.shen
* @date: Created in 2019-02-13 10:32
* @copyright: Copyright (c) 2019
* @version: V1.0
* @modified: yangkai.shen
*/
public abstract class Candy {

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

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

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.simplefactory
* @description: 柠檬味糖果
* @author: yangkai.shen
* @date: Created in 2019-02-13 10:34
* @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.simplefactory
* @description: 西瓜味糖果
* @author: yangkai.shen
* @date: Created in 2019-02-13 10:36
* @copyright: Copyright (c) 2019
* @version: V1.0
* @modified: yangkai.shen
*/
public class WatermelonCandy extends Candy {
/**
* 口味
*/
@Override
public void taste() {
System.out.println("西瓜味");
}
}

4.3. 步骤三:创建糖果工厂

CandyFactory.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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
* <p>
* 糖果工厂类
* </p>
*
* @package: com.xkcoding.design.pattern.creational.simplefactory
* @description: 糖果工厂类
* @author: yangkai.shen
* @date: Created in 2019-02-13 10:43
* @copyright: Copyright (c) 2019
* @version: V1.0
* @modified: yangkai.shen
*/
public class CandyFactory {
/**
* 生产糖果
*
* @param taste 具体口味
* @return 对应口味的糖果
*/
public Candy produceCandy(String taste) {
if ("lemon".equalsIgnoreCase(taste)) {
return new LemonCandy();
} else if ("watermelon".equalsIgnoreCase(taste)) {
return new WatermelonCandy();
}
return null;
}

/**
* 生产糖果
* @param c 具体口味的糖果类
* @return 对应口味的糖果
*/
public Candy produceCandy(Class c) {
Candy candy = null;
try {
candy = (Candy) Class.forName(c.getSimpleName()).newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
e.printStackTrace();
}
return candy;
}
}

4.4. 步骤四:调用工厂类生产具体口味的糖果

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
import com.xkcoding.design.pattern.creational.simplefactory.Candy;
import com.xkcoding.design.pattern.creational.simplefactory.CandyFactory;
import com.xkcoding.design.pattern.creational.simplefactory.LemonCandy;
import com.xkcoding.design.pattern.creational.simplefactory.WatermelonCandy;

/**
* <p>
* 简单工厂模式测试类
* </p>
*
* @package: com.xkcoding.design.pattern.creational.simplefactory.run
* @description: 简单工厂模式测试类
* @author: yangkai.shen
* @date: Created in 2019-02-13 10:40
* @copyright: Copyright (c) 2019
* @version: V1.0
* @modified: yangkai.shen
*/
public class PatternTest {
public static void main(String[] args) {
CandyFactory factory = new CandyFactory();
// 测试工厂类方法 - 1
Candy candy1 = factory.produceCandy("lemon");
candy1.taste();
Candy candy2 = factory.produceCandy("watermelon");
candy2.taste();

// 测试工厂类方法 - 2
Candy candy3 = factory.produceCandy(LemonCandy.class);
candy3.taste();
Candy candy4 = factory.produceCandy(WatermelonCandy.class);
candy4.taste();
}
}

5. 应用

1
2
// Slf4j日志
// 获取日志对象 -> LoggerFactory.getLogger(String name) -> getILoggerFactory() -> getLogger(name)

6. 场景

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

7. 优缺点

优点: 以本例为例,1、糖果调用方想创建一个具体口味的糖果对象,只要知道其口味就可以。 2、扩展性高,如果想增加一个具体口味的糖果,只要在工厂类中添加一种生产逻辑就可以实现。 3、屏蔽糖果的具体实现,调用方只关心抽象实体的通用接口在具体口味糖果类中的不同实现。

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

8. 完整代码地址

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

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