工厂模式分为简单工厂,工厂方法模式和抽象工厂模式。
简单工厂
简单工厂其实不是一个设计模式,反而更像是一种编程习惯,它是指创建对象时不再直接使用 new ,而是把创建的过程委托给一个工厂类,这样客户端类不再依赖具体的实现类,只需要依赖工厂类,给出具体的参数给工厂类,工厂类就会返回对应的实例对象。这种适合在根据大量判断条件创建不同类型时使用,工厂将具体的对象跟客户端解藕,并且更加具有可重用性。
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
/**
* 简单披萨工厂
*/
public class SimplePizzaFactory {
/**
* 根据不同类型创建对应的披萨
* @param type 披萨类型
* @return
*/
public Pizza createPizza(String type){
if (type.equals("cheese")){
return new CheesePizza();
}else if(type.equals("clam")){
return new ClamPizza();
}else {
return new CheesePizza();
}
}
}
/**
* 客户端
*/
public class PizzaStore {
/**
* 简单披萨工厂
*/
SimplePizzaFactory factory;
public PizzaStore(SimplePizzaFactory factory){
this.factory = factory;
}
public Pizza orderPizza(String type){
// 将具体类型的披萨委托给简单工厂生产
Pizza pizza = factory.createPizza(type);
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
从上面可以看出,客户端不再创建具体的 CheesePizza
或 ClamPizza
对象,创建的细节移到了工厂,如果披萨的类型增加了,或者创建过程发生了变化,都不需要修改客户端代码,只需要修改工厂就行了。
工厂方法模式
上面讲到的简单工厂将创建具体对象的过程剥离了出来,带来了很多优点,但是也有明显的缺点,假设要创建的类型很多的话,就需要在工厂类中写很多的判断条件,会导致庞大臃肿,每次增加或删除种类都需要打开工厂类进行修改,违背了开放-关闭原则。
工厂方法模式可以对简单工厂进一步解藕,解决上面的问题。
工厂方法模式定义了一个创建对象的接口,但是由子类决定要实例化的类是哪一个,工厂方法让类把实例化推迟到子类。
工厂方法模式是将简单工厂里面的多个类拆分到单个的工厂,也就是每一种类型都有自己的工厂子类(需要实现工厂“接口”),这样就避免了单个工厂类的臃肿问题,进一步降低了耦合。
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
/**
* 工厂接口,也可以是一个含有抽象方法的超类
*/
public interface Factory {
/**
* 必须含有创建对象的方法
* @return
*/
Pizza createPizza();
}
/**
* 工厂子类,只创建CheesePizza
*/
public class CheesePizzaFactory implements Factory {
@Override
public Pizza createPizza() {
return new CheesePizza();
}
}
/**
* 工厂子类,只创建ClamPizza
*/
public class ClamPizzaFactory implements Factory {
@Override
public Pizza createPizza() {
return new ClamPizza();
}
}
/**
* 客户端
*/
public class PizzaStore2 {
public Pizza orderPizza(){
//需要什么类型,则创建对应的工厂类
Factory factory = new CheesePizzaFactory();
Pizza pizza = factory.createPizza();
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
工厂方法模式中,创建一种对象需要创建对应的工厂类,虽然将创建对象的细节剥离到了工厂类,但是这样在客户端中就需要new一个具体的工厂类了,虽然有办法避免这样的问题,但还是有些不理解,可能是应用的场景不同,上述例子并不是很合适。
###抽象工厂模式
抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体的类。
看书给我的粗略理解是,按类型划分要创建的工厂(一类产品一个工厂)和产品(具体对象),首先定一个工厂接口,然后按类型实现工厂的子类,同时定义产品的接口,所有工厂产生的产品都需要实现产品的接口。抽象工厂允许客户使用抽象的接口来创建一组相关的产品,而不需要知道实际产出的产品是什么,这样一来,客户端就从具体的产品中被解藕。结合书上的类图会更好理解一些。
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/**
* 工厂接口,也可以是一个含有抽象方法的超类
*/
public interface Factory {
/**
* 必须含有创建对象的方法
* @return
*/
Pizza createPizza(String type);
}
/**
* 披萨接口,所有不同风格的披萨都需要实现此接口
*/
public interface Pizza {
void bake();
void cut();
void box();
}
/**
* 纽约风格披萨工厂类
*/
public class NyPizzaFactory implements Factory {
@Override
public Pizza createPizza(String type) {
Pizza pizza;
if (type.equals("cheesePizza")){
// 创建纽约风格的芝士披萨
pizza = new NyCheesePizza();
}else {
// 创建纽约风格的其他披萨
pizza = new NyOtherPizza();
}
return pizza;
}
}
/**
* 披萨的具体实现,纽约风格的芝士披萨
*/
public class NyCheesePizza implements Pizza {
@Override
public void bake() {
}
@Override
public void cut() {
}
@Override
public void box() {
}
}
/**
* 客户端
*/
public class PizzaStore3 {
public Pizza orderPizza(){
//需要什么风格类型,则创建对应的工厂类
Factory factory = new NyPizzaFactory();
Pizza pizza = factory.createPizza("cheesePizza");
pizza.bake();
pizza.cut();
pizza.box();
return pizza;
}
}
总结
看一遍书,对工厂模式有了大概是认识。简单工厂是一个工厂创建多种对象,将对象的创建细节剥离了出来,减少了客户端的依赖。工厂方法模式是更进一步将工厂拆分,一个工厂只生产一种产品,减少了单个工厂的臃肿。最后抽象工厂模式则是将产品和工厂都抽象到接口,客户端不关心具体调用的是哪个工厂,将得到什么产品,只需要制订好需要的产品类型就好了,这样就更加灵活了。