工厂模式

工厂模式概述

工厂模式是一种用于创建对象的设计模式,其核心在于把获得某种对象的过程从程序中解耦出来,成为一个单独的模块。

这样做为什么是必要的呢?在一些时候,获得对象只需要一行简单的 new 语句,此时确实没有将其封装的必要;但在实际场景中,创建一个对象的过程也许会更为复杂。

举个例子,假设 A 对象的创建依赖 B 对象和 C 对象:

1
2
3
4
5
B b = new B();
// do something to b
C c = new C();
// do something to c
A a = new A(b,c);

假设有十个模块都用这种方式创建 A 对象,那么如果某天想把 A 对象的创建改为依赖一个 D 对象,我们就只能把这十个模块手动改一遍。

如果我们用了工厂模式的设计思想,把上面的过程封装成到一个工厂类:

1
2
3
4
5
6
7
8
9
10
public class Factory{
public A CreateA(){
B b = new B();
// do something to b
C c = new C();
// do something to c
A a = new A(b,c);
return A;
}
}

而其他模块都通过工厂类来获取A对象:

1
2
Factory f = new Factory();
A = f.CreateA();

那么后续A的创建过程被修改时,我们只要修改Factory类就可以了。

工厂模式具体实现

工厂模式的思想我们已经清楚了,在实践中,工厂模式大体上有三种实现形式,即:

  • 简单工厂模式
  • 工厂方法模式
  • 抽象工厂模式

假设有两个类Phone和Tablet,都继承自抽象类Device,我们来考察不同的工厂模式如何创建所需的对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public abstract class Device{
public abstract void work();
}

public class Phone extends Device{
@Override
public void work(){
System.out.println("A phone is working");
}
}

public class Tablet extends Device{
@Override
public void work(){
System.out.println("A tablet is working");
}
}

简单工厂模式

这种实现方式定义一个工厂类,在这个类中实现所有对象的创建:

1
2
3
4
5
6
7
8
9
10
public class DeviceFactory{
public Device createDevice(int deviceType){
if (deviceType == 0) {
return new Phone();
} else if (deviceType == 1) {
return new Tablet();
}
return null;
}
}

这样写的优点在于不必在原有基础上添加过多的代码,而且便于控制创建不同对象的逻辑。比如游戏中敌人被击败时掉落道具的代码,创建何种道具对象的逻辑可能十分复杂,就适合采用此种方式。

而此方法的缺点是,后续增加对象时,不得不修改现有的代码,系统的可扩展性一般。

工厂方法模式

此方法定义一个创建对象的抽象接口,用不同的子类实现创建具体对象的方法:

1
2
3
public interface DeviceFactory{
Device createDevice();
}
1
2
3
4
5
6
public class PhoneFactory implements DeviceFactory{
@Override
public Device createDevice(){
return new Phone();
}
}
1
2
3
4
5
6
public class TabletFactory implements DeviceFactory{
@Override
public Device createDevice(){
return new Tablet();
}
}

这种方式的优点是后续增加对象时,不需要修改已有代码,只需增加新的子类,整个项目架构十分清晰,可扩展性高。

缺点也是明显的,即代码量大,而且本身无法实现不同对象创建的逻辑,只关注于对象的创建过程本身。

抽象工厂模式

上面提到的工厂方法模式,其工厂只负责创建一种对象,而此种模式下一种工厂负责创建一类对象。

在上面举的例子中,我们把Phone和Tablet改为抽象类,并为它们添加子类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public abstract class Phone extends Device{

}

public class HuaweiPhone extends Phone{
@Override
public void work(){
System.out.println("A HuaweiPhone is working");
}
}

public class XiaomiPhone extends Phone{
@Override
public void work(){
System.out.println("A XiaomiPhone is working");
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public abstract class Tablet extends Device{

}

public class HuaweiTablet extends Tablet{
@Override
public void work(){
System.out.println("A HuaweiPhone is working");
}
}

public class XiaomiTablet extends Tablet{
@Override
public void work(){
System.out.println("A XiaomiTablet is working");
}
}

对于四种对象,如果用工厂方法模式,需要四种工厂。但这四种对象继承自两种抽象类,这意味着我们其实可以用两种工厂完成创建:

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
public interface DeviceFactory{
Phone createPhone();
Tablet createTablet();
}

public class HuaweiFactory implements DeviceFactory{
@Override
public Phone createPhone(){
return new HuaweiPhone();
}

@Override
public Tablet createTablet(){
return new HuaweiTablet();
}
}

public class XiaomiFactory implements DeviceFactory{
@Override
public Phone createPhone(){
return new XiaomiPhone();
}

@Override
public Tablet createTablet(){
return new XiaomiTablet();
}
}

这就是所谓抽象工厂模式,其本质是对工厂进行了一层抽象:把原来所需的四种工厂,根据创建对象的某些共性抽象为两种。此方法适用于对象有较多继承关系的场景,可以减少工厂方法模式需要的工厂数量。缺点是扩展性弱,例如后续增加一个earphone抽象类,就需要修改所有工厂类。

总结

工厂模式体现了面向对象中“各司其职”的思想,是为了把复杂的业务逻辑划分到不同模块,降低耦合程度,以提高代码的复用性,便于开发和后期维护。


工厂模式
https://ch3chohch3.github.io/2022/03/22/factory_pattern/
作者
CH3CHOHCH3
发布于
2022年3月22日
许可协议