咸鱼开发修炼之路

设计模式-工厂模式

简介

在面向对象编程中, 最通常的方法是一个new操作符产生一个对象实例,new操作符就是用来构造对象实例的。但是在一些情况下, new操作符直接生成对象会带来一些问题。
举例来说, 许多类型对象的创造需要一系列的步骤: 你可能需要计算或取得对象的初始设置; 选择生成哪个子对象实例; 或在生成你需要的对象之前必须先生成一些辅助功能的对象。
又比如某个接口有很多实现类,如果使用new的方式创建对象,就需要用户了解具体应该使用哪个类,如果每个类实例化的参数还不一样,对用户来说就非常麻烦。此时工厂模式就派上了用处,用户只需告诉工厂自己需要哪种对象,由工厂来判断应当创建哪种对象并返回给用户。
f4e52909.png

Spring 中bean的创建就是典型的工厂模式,他的顶级接口是 BeanFactory,下图是这个工厂的继承层次关系:
07908e6c.png

工厂模式又可以分为简单工厂,抽象工厂方法和抽象工厂三种类型。 GOF在《设计模式》一书中将工厂模式分为两类:工厂方法模式(Factory Method)与抽象工厂模式(Abstract Factory)。将简单工厂模式(Simple Factory)看为工厂方法模式的一种特例,两者归为一类。

简单工厂

我们经常一些功能类似的类,所以我们的思路是对进行抽象,使用接口暴露公共的方法,使用抽象类来提供公共的实现。

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
public interface IProduct {
void print(); // 这是要暴露的方法
}
public abstract class AbstractProduct implements IProduct {
protected void printBefore(){
System.out.println("before print"); // 这里所公共的实现
}
}
public class AProduct extends AbstractProduct {
private String name;
public AProduct(String name){
this.name = name;
}
@Override
public void print() {
this.printBefore();
System.out.println("print A >>>"+name);
}
}
public class BProduct extends AbstractProduct {
private String name;
public BProduct(String name){
this.name = name;
}
@Override
public void print() {
this.printBefore();
System.out.println("print B >>>"+name);
}
}

这些功能类似的类的实例化成为了一个问题,每个类的构造方法参数还不一样,每次 new 对象很麻烦,封装成简单工厂模式。
1
2
3
4
5
6
7
8
9
10
11
public class SimpleFactory {
public static IProduct getProduct(String name){
if("A".equals(name)){
return new AProduct(name);
}else if("B".equals(name)){
return new BProduct(name);
}else{
throw new IllegalArgumentException();
}
}
}

抽象工厂方法

简单工厂模式不利于拓展,违背了开闭原则,每次添加一个类,都要修改工厂类(如果是工厂类和业务类是两个小伙伴分开写的,那不是要花很多时间来沟通…),所以就有工厂方法模式,其原理就是对简单工厂也进行抽象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public interface IFactory {
IProduct getProduct();
}
public class AFactory implements IFactory {
@Override
public IProduct getProduct() {
return new AProduct(AProduct.class.getName());
}
}
public class BFactory implements IFactory {
@Override
public IProduct getProduct() {
return new BProduct(BProduct.class.getName());
}
}

抽象工厂

第 4 个问题:功能类似的产品我们进行 3 层抽象,针对每个产品我们还抽象出了 2 层的工厂类,代码量一下子增加了很多。
但是我们在某个具体的业务场景中,不单单是只实例化一个类啊。举一个例子,要造一个汽车,汽车由多个部件组成,如发动机、轮子、方向盘等等,这就需要汽车厂能同时建造这多种部件,组装成汽车。
这就是抽象工厂模式。简单来说,可以把有一些有联系或者相近的产品,放到一个工厂去生产,没有必要单独再开一个工厂了。

例如,现在要生产便宜的汽车和昂贵的汽车,每种汽车用的零件类型也有昂贵和便宜的区别:代码: github

dc67b694.png
1
2
3
4
5
6
7
8
9
10
/**
* 抽象工厂类,定义抽象方法
*
* 抽象工厂方法:围绕一个超级工厂创建其他工厂,生产出成系列的对象
* Created by ssc on 2017/12/17.
*/
public abstract class AbstractCarFactory {
abstract Wheel getWheel();
abstract Engine getEngine();
}
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
/**
* 具体工厂实现类,根据具体需求创建对象
* 便宜汽车的工厂
* Created by ssc on 2017/12/17.
*/
public class CheepCarFactory extends AbstractCarFactory {
private static CheepCarFactory cheepCarFactory;
private CheepCarFactory(){}
public static AbstractCarFactory getInstance(){
if(cheepCarFactory == null){
cheepCarFactory = new CheepCarFactory();
}
return cheepCarFactory;
}
@Override
Wheel getWheel() {
return new CheepWheel();
}
@Override
Engine getEngine() {
return new CheepEngine();
}
}
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
/**
* 具体工厂实现类,根据具体需求创建对象
* 昂贵汽车的工厂
* Created by ssc on 2017/12/17.
*/
public class ExpensiveCarFactory extends AbstractCarFactory {
private static ExpensiveCarFactory expensiveCarFactory;
private ExpensiveCarFactory(){}
public static ExpensiveCarFactory getInstance(){
if(expensiveCarFactory == null){
expensiveCarFactory = new ExpensiveCarFactory();
}
return expensiveCarFactory;
}
@Override
Wheel getWheel() {
return new ExpensiveWheel();
}
@Override
Engine getEngine() {
return new ExpensiveEngine();
}
}

部件1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public abstract class Wheel {
abstract String getName();
}
public class ExpensiveWheel extends Wheel {
@Override
String getName() {
return "expensive wheel";
}
}
public class CheepWheel extends Wheel{
@Override
String getName() {
return "cheep wheel";
}
}

部件2:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public abstract class Engine {
abstract String getName();
}
public class ExpensiveEngine extends Engine {
@Override
String getName() {
return "expensive engine ";
}
}
public class CheepEngine extends Engine{
@Override
String getName() {
return "cheep engine";
}
}

用来调用具体工厂并进行汽车组装的类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class CarProducer {
public static AbstractCarFactory getFactory(String type){
if(type.equals("expensive")){
return ExpensiveCarFactory.getInstance();
}else if(type.equals("cheep")){
return CheepCarFactory.getInstance();
}
return null;
}
public static Car getCar(String type){
Engine engine = getFactory(type).getEngine();
Wheel wheel = getFactory(type).getWheel();
Car car = new Car();
car.setEngine(engine);
car.setWheel(wheel);
return car;
}
}

测试:

1
2
3
4
5
6
7
8
public class Client {
public static void main(String[] args){
Car car1 = CarProducer.getCar("cheep");
car1.run();
Car car2 = CarProducer.getCar("expensive");
car2.run();
}
}

运行结果:

1
2
This is a car with cheep wheel and cheep engine
This is a car with expensive wheel and expensive engine

总结

  1. 三种工厂的实现是越来越复杂的
  2. 简单工厂通过构造时传入的标识来生产产品,不同产品都在同一个工厂中生产,这种判断会随着产品的增加而增加,给扩展和维护带来麻烦
  3. 工厂模式无法解决产品族和产品等级结构的问题
  4. 抽象工厂模式中,一个工厂生产多个产品,它们是一个产品族,不同的产品族的产品派生于不同的抽象产品(或产品接口)。

参考

https://www.ibm.com/developerworks/cn/java/designpattern/factory/
https://www.zhihu.com/question/24843188?sort=created
http://www.runoob.com/design-pattern/abstract-factory-pattern.html