lusiqi

设计模式-工厂模式,介绍工三种工厂模式,及代码实现。


简介

工厂模式属于创建型模式,提供了创建对象的最佳方式,定义了一个创建对象的接口,让其子类自己决定实例化哪个工厂类,工厂模式使其创建过程延迟到子类进行。

优势

  • 解耦,创建对象和使用对象分开
  • 降低代码的重复
  • 降低维护成本

分类

工厂模式可以分成三类:

  • 简单工厂模式,又称静态工厂模式
  • 工厂方法模式,又称多态性工厂模式
  • 抽象工厂模式,又称工具箱模式

本文代码参考大话设计模式,即用java实现工厂模式。需求:用java代码实现简单计算器功能,包括加减乘除等功能。

简单工厂

简单工厂模式适合简单的场景,因为如果新增功能进行维护时,需要修改原来代码,在switch/if 代码修改添加,这样的话就违反了设计模式的开闭原则

角色
  • 工厂角色:对外开放接口,调用者通过调用工厂的方法获得实例,工厂内部方法通过外部传入的参数实例化需要的具体实例
  • 抽象类角色:具体实例的父类,负责描述所有实例的公共接口(计算接口)
  • 具体类角色:简单工厂模式的创建目标,创建的对象为具体操作的实例(具体的计算操作类,加减乘除)
实现设计
  1. 创建计算器操作的操作抽象类
  2. 创建计算子类加减乘除类分别继承操作抽象类
  3. 创建工厂类,创建计算方法,可通过计算的标识,获得具体的操作类
  4. 客户端可通过调用工厂类,实现计算器功能
代码实现

操作抽象类

1
2
3
4
5
6
7
8
9
10
11
/**
* @description 操作类抽象类
* @author dxy
* @date 20200109
*/
public abstract class Operation {
public double numberA;
public double numberB;

public abstract double result();
}

具体操作类

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
48
49
50
51
52
53
54
55
56
/**
* @description 加法类
* @author dxy
* @date 20200109
*/
public class OperationAdd extends Operation {

@Override
public double result() {
return numberA + numberB;
}

}

/**
* @description 减法类
* @author dxy
* @date 20200109
*/
public class OperationSub extends Operation {

@Override
public double result() {
return numberA - numberB;
}

}
/**
* @description 乘法类
* @author dxy
* @date 20200109
*/
public class OperationMul extends Operation {

@Override
public double result() {
return numberA * numberB;
}

}
/**
* @description 除法类
* @author dxy
* @date 20200109
*/
public class OperationDiv extends Operation {

@Override
public double result() {
if (numberB == 0) {
throw new RuntimeException("除数不可以为0!");
}
return numberA / numberB;
}

}

工厂类

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
/**
* @description 操作类工厂类
* @author dxy
* @date 20200109
*/
public class OperationFactory {
public static Operation createOperation(char operator) {
Operation operation = null;

switch (operator) {
case '+':
operation = new OperationAdd();
break;
case '-':
operation = new OperationSub();
break;
case '*':
operation = new OperationMul();
break;
case '/':
operation = new OperationDiv();
break;
default:
throw new RuntimeException("unsupported operation");
}

return operation;
}
}

客户端调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
/**
* @description 计算器客户端,调用工厂类获得计算操作实例,完成计算操作
* @author dxy
* @date 20200109
*/
public class Calculator {
public static void main(String[] args) {
Operation operation;
char operator;

operator = '*';
operation = OperationFactory.createOperation(operator);
operation.numberA = 1;
operation.numberB = 2;

System.out.println(operation.result());
}
}
改善

可通过反射改善简单工厂模式的“违反开闭原则”,即在工厂类获得实例的方法中,通过类的方式来获得类,配合配置文件可灵活配置。

工厂方法

工厂方法模式是简单工厂的进一步深化,工厂方法模式不在提供统一的工厂类来创建所有的对象,而是针对不同的对象提供不同的工厂。

角色
  • 抽象工厂角色
  • 具体工厂角色
  • 抽象实例角色
  • 具体实例角色
实现设计
  1. 创建抽象的工厂接口,定义统一的获取实例的方法
  2. 创建获取加减乘除实例的工厂,实现抽象工厂接口
  3. 创建抽象实例操作类,定义结果方法、操作数属性(同简单工厂)
  4. 创建具体实例类,继承抽象实例(真正的加减乘除,同简单工厂)
代码实现

抽象工厂接口

1
2
3
4
5
6
7
8
9
/**
* @description 抽象工厂接口
* @author dxy
* @date 20200109
*/
public interface IFactory {

Operation createOperation();
}

具体工厂

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
48
49
50
51
52
/**
* @description 加法工厂
* @author dxy
* @date 20200109
*/
public class AddFactory implements IFactory {

@Override
public Operation createOperation() {
return new OperationAdd();
}

}
/**
* @description 减法工厂
* @author dxy
* @date 20200109
*/
class SubFactory implements IFactory {

@Override
public Operation createOperation() {
return new OperationSub();
}

}
/**
* @description 乘法工厂
* @author dxy
* @date 20200109
*/
class MulFactory implements IFactory {

@Override
public Operation createOperation() {
return new OperationMul();
}

}
/**
* @description 除法工厂
* @author dxy
* @date 20200109
*/
class DivFactory implements IFactory {

@Override
public Operation createOperation() {
return new OperationDiv();
}

}

客户端调用

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
/**
* @description 工厂方法客户端
* @author dxy
* @date 20200109
*/
public class FactoryClient {
public static void main(String[] args) {

//除法
IFactory divFactory = new DivFactory();
Operation div = divFactory.createOperation();
div.numberA = 3;
div.numberB = 4;

System.out.println(div.result());
//加法
IFactory addFactory = new AddFactory();
Operation add = addFactory.createOperation();
add.numberA = 3;
add.numberB = 4;

System.out.println(add.result());
//乘法
IFactory mulFactory = new MulFactory();
Operation mul = mulFactory.createOperation();
mul.numberA = 3;
mul.numberB = 4;

System.out.println(mul.result());
//减法
IFactory subFactory = new DivFactory();
Operation sub = subFactory.createOperation();
sub.numberA = 3;
sub.numberB = 4;

System.out.println(sub.result());

}
}
缺点

由于具体工厂都实现了相同的接口,即获得实例方法的返回实例是相同的。也就是说工厂方法获得实例都必须继承同一父类,通过工厂方法只能获得同一“品类”(相同父类)的实例。

抽象工厂

抽象工厂模式是对工厂方法模式的改进,用于处理实例不是同一类的情况,将实例都继承同一抽象类,改为实现接口。

角色
  • 抽象工厂角色
  • 具体工厂角色
  • 抽象实例角色
  • 具体实例角色
实现设计
  1. 创建抽象工厂接口,定义两个方法,分别是一个获取加法减法接口的方法、一个是获取乘法除法接口的方法
  2. 创建获取加法乘法实例的具体工厂,和获取减法除法实例的具体工厂
  3. 创建加法减法的抽象实例接口,和乘法除法的抽象实例接口
  4. 创建加法减法实例实现加法减法接口,创建乘法除法实例实现相应接口
代码实现

抽象工厂接口

1
2
3
4
5
6
7
8
9
10
11
12
/**
* @description 抽象工厂接口
* @author dxy
* @date 20200109
*/
public interface IAbsFactory {

IOperationAddSub createOperationAddSub();


IOperationMulDiv createOperationMulDiv();
}

具体工厂

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
/**
* @description 加法乘法工厂
* @author dxy
* @date 20200109
*/
public class AddMulAbsFactory implements IAbsFactory {


@Override
public IOperationAddSub createOperationAddSub() {

return new OperationAbsAdd();
}

@Override
public IOperationMulDiv createOperationMulDiv() {

return new OperationAbsMul();
}
}

/**
* @description 减法除法工厂
* @author dxy
* @date 20200109
*/
public class SubDivAbsFactory implements IAbsFactory {


@Override
public IOperationAddSub createOperationAddSub() {

return new OperationAbsSub();
}

@Override
public IOperationMulDiv createOperationMulDiv() {

return new OperationAbsDiv();
}
}

抽象实例接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* @description 加减操作类型接口
* @author dxy
* @date 20200109
*/
public interface IOperationAddSub {

double result(double numberA,double numberB);
}

/**
* @description 乘除操作类型接口
* @author dxy
* @date 20200109
*/
public interface IOperationMulDiv {

double result(double numberA,double numberB);
}

具体实例

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
48
49
50
51
52
53
54
55
56
57
58
59
60
61
/**
* @description 加法类
* @author dxy
* @date 20200109
*/
public class OperationAbsAdd implements IOperationAddSub{


@Override
public double result(double numberA,double numberB) {
return numberA + numberB;
}

}

/**
* @description 减法类
* @author dxy
* @date 20200109
*/
public class OperationAbsSub implements IOperationAddSub {


@Override
public double result(double numberA,double numberB) {

return numberA - numberB;
}

}

/**
* @description 乘法类
* @author dxy
* @date 20200109
*/
public class OperationAbsMul implements IOperationMulDiv {

@Override
public double result(double numberA,double numberB) {
return numberA * numberB;
}

}

/**
* @description 除法类
* @author dxy
* @date 20200109
*/
public class OperationAbsDiv implements IOperationMulDiv {

@Override
public double result(double numberA,double numberB) {
if (numberB == 0) {
throw new RuntimeException("除数不可以为0!");
}
return numberA / numberB;
}

}
优缺点
  • 优点:对工厂方法的改进,通过抽象工厂返回接口,可获得多种类的实例,不局限为必须是相同种类。

  • 缺点:代码实现较复杂

 评论