设计模式之工厂模式(工厂三兄弟)

简单工厂模式

定义

简单工厂模式又叫静态工厂方法模式。
通过定义一个工厂类,根据传入的不同参数,创建不同的实例对象。这些实例对象具有共同的父类或接口。

实现
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
//抽象产品
public interface Product {
public void productName();
}
//具体产品
public class ProductA implements Product{
@Override
public void productName() {
System.out.println("产品A");
}
}
public class ProductB implements Product {
@Override
public void productName() {
System.out.println("产品B");
}
}
//工厂类
public class SimpleFactory {
public static Product createProduct(String productName) {
switch (productName) {
case "A" :
return new ProductA();
case "B" :
return new ProductB();
default: return null;
}
}
}
1
2
3
4
5
6
7
8
public static void main(String[] args) {
//创建产品A
Product productA = SimpleFactory.createProduct("A");
productA.productName();
//创建产品B
Product productB = SimpleFactory.createProduct("B");
productB.productName();
}

从上面的代码可以看到,如果需要引入新的产品,那么就要改动SimpleFactory类,这就违反了开闭原则。可以利用反射来解决该问题,在配置文件中指定类的完整类名,在SimpleFactory类中通过反射实例化对象。实现了对扩展的开放,同时保证了对修改的关闭。

优点
  1. 工厂类是整个简单工厂模式的关键。用户在使用时可以直接根据工厂类去创建所需的实例,而无需了解这些对象是如何创建以及如何组织的。客户端不关心对象的创建过程。
  2. 通过引入配置文件和反射,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类。
缺点
  1. 由于工厂类集中了所有实例的创建逻辑,这就直接导致一旦这个工厂出了问题,所有的客户端都会受到牵连
  2. 简单工厂模式违背了“开放-关闭原则”,因为当我们新增加一个产品的时候必须修改工厂类,相应的工厂类就需要重新编译一遍。
  3. 违背了单一职责原则(工厂类即要负责逻辑判断又要负责实例创建

应用简单工厂模式在JDK中最典型的应用要数JDBC了。可以把关系型数据库认为是一种抽象产品,各厂商提供的具体关系型数据库(MySQL,PostgreSQL,Oracle)则是具体产品。DriverManager是工厂类。应用程序通过JDBC接口使用关系型数据库时,并不需要关心具体使用的是哪种数据库,而直接使用DriverManager的静态方法去得到该数据库的Connection。

1
Connection connect = DriverManager.getConnection("jdbc:mysql://localhost:3306/test");

工厂方法模式

定义

工厂方法模式又称工厂模式。
工厂父类定义创建产品对象的公共接口,具体的工厂子类负责创建具体的产品对象。通过不同的工厂子类来创建不同的产品

简单工厂只有一个统一的工厂类,而工厂方法是针对每一个对象都有一个工厂类,这些工厂类都实现了工厂基类。

实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//工厂类A
public class FactoryA implements Factory {
@Override
public Product create() {
return new ProductA();
}
}
//工厂类B
public class FactoryB implements Factory {
@Override
public Product create() {
return new ProductB();
}
}
1
2
3
4
5
6
7
8
9
10
11
public static void main(String[] args) {
//创建产品A
Factory factoryA = new FactoryA();
Product productA = factoryA.create();
productA.productName();
//创建产品B
Factory factoryB = new FactoryB();
Product productB = factoryB.create();
productB.productName();
}
优点:
  1. 每个工厂类只负责创建产品,没有简单工厂中的逻辑判断,符合单一职责原则。
  2. 客户端不知道它所要创建对象的类,只需要知道工厂名就完成了对象的创建。
  3. 新增一种产品时,只需要增加相应的具体产品类和相应的工厂子类即可。
缺点:
  1. 添加新产品时,除了增加新产品类外,还要增加与之对应的具体工厂类,类的个数将成对增加,在一定程度上增加了系统的复杂度。
  2. 一个具体工厂只能创建一种具体产品。

抽象工厂模式

抽象工厂是工厂方法的进一步深化,在这个模式中的工厂类不单单可以创建一个对象,而是创建一组对象。(工厂方法模式中一种工厂只能创建一种具体产品)

抽象工厂模式与工厂方法模式最大的区别:抽象工厂中每个工厂可以创建多种类的产品;而工厂方法每个工厂只能创建一种类的产品。

每一个具体工厂都提供了多个工厂方法用于产生多种不同类型的对象。

实现
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
//抽象工厂
public interface AbstractFactory {
public ProductPhone createproductPhone();
public ProductPC createproductPC();
}
//苹果工厂
public class FactoryApple implements AbstractFactory {
@Override
public ProductPhone createproductPhone() {
return new ApplePhone();
}
@Override
public ProductPC createproductPC() {
return new ApplePC();
}
}
//Vioio工厂
public class FactoryVioio implements AbstractFactory {
@Override
public ProductPhone createproductPhone() {
return new VioioPhone();
}
@Override
public ProductPC createproductPC() {
return new VioioPC();
}
}
//抽象产品
public interface ProductPhone {
public void show();
}
public interface ProductPC {
public void show(); //不一定是show方法
}
//具体产品
public class ApplePhone implements ProductPhone {
@Override
public void show() {
System.out.println("一个苹果手机");
}
}
public class ApplePC implements ProductPC {
@Override
public void show() {
System.out.println("一个苹果电脑");
}
}
public class VioioPhone implements ProductPhone {
@Override
public void show() {
System.out.println("一个Vioio手机");
}
}
public class VioioPC implements ProductPC{
@Override
public void show() {
System.out.println("一个Vioio电脑");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public static void main(String[] args) {
//苹果工厂
FactoryApple factoryApple = new FactoryApple();
ProductPhone productPhone = factoryApple.createproductPhone();
productPhone.show();
ProductPC productPC = factoryApple.createproductPC();
productPC.show();
//Vioio工厂
FactoryVioio factoryVioio = new FactoryVioio();
ProductPhone productPhone1 = factoryVioio.createproductPhone();
productPhone1.show();
ProductPC productPC1 = factoryVioio.createproductPC();
productPC1.show();
}
抽象工厂模式角色
  • 抽象工厂。如AbstractFactory
  • 具体工厂。如FactoryApple,FactoryVioio
  • 抽象产品。如ProductPhone、ProductPC
  • 具体产品。如ApplePhone、ApplePC、VioioPhone、VioioPC
  • 产品族。包含两个产品:Phone、PC。
优点
  1. 每个具体工厂类只负责创建产品,没有简单工厂中的逻辑判断,因此符合单一职责原则。
  2. 新增一个产品族(如代码中一个产品族包含两个产品:Phone、PC)时,只需要增加相应的具体产品和对应的具体工厂类即可。
缺点
  1. 新增产品种类(如在产品族中增加一个平板)时,需要修改工厂接口(或者抽象工厂)及所有具体工厂,此时不符合开闭原则。抽象工厂模式对于新的产品族符合开闭原则,而对于新的产品种类不符合开闭原则,这一特性也被称为开闭原则的倾斜性。