0%

GoF设计模式(三):Factory Pattern 工厂模式

很多时候我们只是期望获取对象实例即可,并不关心实例构造过程(例如相关Field的具体如何设置)。这个时候就可以将通过工厂模式来解决这个问题,其同样也是一种创建型模式。将实例的具体构造过程进行封装以对外屏蔽,就像现实世界中我们只需从工厂直接拿取产品即可,而无需care产品在工厂里的具体制造过程

abstract.jpeg

Simple Factory Pattern 简单工厂模式

假设有三种品牌的汽车:BMW宝马、Benz奔驰、Rolls Royce劳斯莱斯。客户订购了其中某一品牌的汽车,那么只需要在汽车工厂把车造好了直接去取就好了,至于车咋造的,相信没有客户会Care吧……实际上在软件工程领域中,这样的需求也经常出现,Client只是需要一个实例对象而已,至于这个对象具体怎么构造的,他不需要也不想知道这么多细节。这个时候就可以借用工厂的概念来解决这个问题,只不过这里的工厂不造车罢了,改为创建实例

这里,我们先来介绍 Simple Factory Pattern 简单工厂模式。其有以下三种角色:

  1. 抽象产品角色:其定义了具体产品的实现类所具有的共有方法,一般通过接口实现。本文中其就是Car接口,其定义了汽车所具备的功能
  2. 具体产品角色:其是抽象产品角色的具体实现类,即是客户真正需要的产品。在这里,即为Benz、BMW、RollsRoyce类
  3. 工厂角色:其是一个工厂类。通过一个静态方法来获取该工厂所构建的对象实例,故简单工厂模式又被称作静态工厂方法模式。具体地,可通过参数来指定所需的具体品牌的汽车

现在,就让我们来通过代码实现 Simple Factory Pattern 简单工厂模式。第一步,先定义一个汽车的接口

1
2
3
4
5
6
/**
* 抽象产品角色: 车
*/
public interface Car {
void drive();
}

然后再提供汽车接口的具体实现类

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
/**
* 具体产品角色:奔驰 Benz
*/
public class Benz implements Car {
@Override
public void drive() {
System.out.println("司机在驾驶Benz");
}
}
...
/**
* 具体产品角色:宝马 BMW
*/
public class BMW implements Car {
@Override
public void drive() {
System.out.println("司机在驾驶BMW");
}
}
...
/**
* 具体产品角色:劳斯莱斯 Rolls Royce
*/
public class RollsRoyce implements Car {
@Override
public void drive() {
System.out.println("司机在驾驶Rolls Royce");
}
}

最后,通过一个CarFactory工厂实现实例的构造、获取

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
/**
* 工厂角色
*/
public class CarFactory {
public static Car getCar(String type) {
if( type==null ) {
return null;
}
Car car = null;
switch (type) {
case "BMW":
car = new BMW();
break;
case "Benz":
car = new Benz();
break;
case "RollsRoyce":
car = new RollsRoyce();
break;
default:
car = null;
}
return car;
}
}

下面通过一个测试用例来演示其使用方式

1
2
3
4
5
6
7
8
9
10
11
12
public class SimpleFactoryDemo {
public static void main(String[] args) {
Car bmw = CarFactory.getCar("BMW");
bmw.drive();

Car benz = CarFactory.getCar("Benz");
benz.drive();

Car rollsRoyce = CarFactory.getCar("RollsRoyce");
rollsRoyce.drive();
}
}

从测试结果可以看出,结果符合预期

figure 1.png

Factory Pattern 工厂模式

前文介绍的Simple Facotry Pattern 简单工厂模式,虽然可以让client不用再关注实例的具体构造过程了,但是其存在一个明显的缺点。每当我们需要添加一个新的Car实现类时,都需要对CarFactory类进行修改。这显然破坏了开闭原则,即对扩展开放、对修改关闭。那如何解决这个问题呢?这个时候就需要引入本文的正题了——Factory Patttern 工厂模式,其又被称作工厂方法模式。该设计模式与简单工厂模式区别、改进之处就在于,其对于工厂的设计是基于接口的思想,具体地,其将简单工厂模式中的工厂角色改进为以下两个角色

  1. 抽象工厂角色:其定义了不同具体产品各自工厂的通用接口
  2. 具体工厂角色:其是抽象工厂的具体实现类,一个具体的工厂类只负责生产某一种产品。这样以后如果需要新的产品,只需添加一个该产品的工厂类即可,而不需要修改之前的代码

显然该设计模式下的抽象产品角色、具体产品角色没有发生变化,所以Car接口及其具体实现类的Benz、BMW、RollsRoyce部分无需改动,如下所示

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
/**
* 抽象产品角色: 汽车
*/
public interface Car {
void drive();
}
...
/**
* 具体产品角色:奔驰 Benz
*/
public class Benz implements Car {
@Override
public void drive() {
System.out.println("司机在驾驶Benz");
}
}
...
/**
* 具体产品角色:宝马 BMW
*/
public class BMW implements Car {
@Override
public void drive() {
System.out.println("司机在驾驶BMW");
}
}
...
/**
* 具体产品角色:劳斯莱斯 Rolls Royce
*/
public class RollsRoyce implements Car {
@Override
public void drive() {
System.out.println("司机在驾驶Rolls Royce");
}
}

现在,我们先来定义一个汽车工厂的接口

1
2
3
4
5
6
/**
* 抽象工厂角色:汽车工厂
*/
public interface CarFactory {
Car getCar();
}

然后,针对三种不同的产品Benz、BMW、RollsRoyce,分别提供各自具体的工厂类

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
/**
* 具体工厂角色:Benz 工厂
*/
public class BenzFactory implements CarFactory{
@Override
public Benz getCar() {
return new Benz();
}
}
...
/**
* 具体工厂角色:BMW 工厂
*/
public class BMWFactory implements CarFactory{
@Override
public BMW getCar() {
return new BMW();
}
}
...
/**
* 具体工厂角色:Rolls Royce 工厂
*/
public class RollsRoyceFactory implements CarFactory{
@Override
public RollsRoyce getCar() {
return new RollsRoyce();
}
}

现在让我们来实际测试下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class FactoryMethodDemo {
public static void main(String[] args) {
CarFactory factory = new BenzFactory();
Car benz = factory.getCar();
benz.drive();

factory = new BMWFactory();
Car bmw = factory.getCar();
bmw.drive();

factory = new RollsRoyceFactory();
Car rollsRoyce = factory.getCar();
rollsRoyce.drive();
}
}

可以看到测试结果,符合预期

figure 2.png

参考文献

  1. Head First 设计模式 弗里曼著
请我喝杯咖啡捏~

欢迎关注我的微信公众号:青灯抽丝