设计模式
把模式装进脑子里,然后在你的设计和已有的应用中,寻找何处可以使用他们

工厂模式

工厂模式是一种创建型设计模式,它提供了一种将对象的实例化过程封装起来的方法。使用工厂模式的主要目的是解耦对象的创建和使用,从而提高代码的灵活性、可维护性和可扩展性

背景

使用 new 关键字创建对象会增加程序的耦合性,使代码难以维护和扩展。例如,针对下面 PC 接口及其实现
PC 接口:电脑标准规范类

1
2
3
public interface PC {
void powerOn();
}

HuaweiPC 类

1
2
3
4
5
6
public class HuaweiPc implements PC{
@Override
public void powerOn() {
System.out.println("华为电脑开机");
}
}

现在,假设有一个 PCApp 类,负责使用 PC 对象

1
2
3
4
5
6
public class PCApp {
public static void main(String[] args) {
PC pc = new HuaweiPc();
pc.powerOn();
}
}

在上述例子中,PCApp 类直接使用 new 关键字实例化了 HuaweiPC 类,这样的做法存在以下问题

  • 紧耦合
    PCApp 类直接依赖于 HuaweiPC 类的具体实现,如果后续我们修改 HuaweiPC 类的构造方法、添加新的属性或者修改类的实现,那么 PCApp 类也必须相应的进行修改
  • 扩展困难
    后续如果增加新的产品,就必须修改客户端代码

为了解决上述的问题,我们可以将对象实例化过程封装起来,对客户端类屏蔽具体实现细节

简单工厂模式

简单工厂模式

继续以创建 PC 为例,增加 XiaomiPC 产品
XiaomiPc 类

1
2
3
4
5
6
public class XiaomiPc implements PC{
@Override
public void powerOn() {
System.out.println("小米电脑开机");
}
}

工厂类

1
2
3
4
5
6
7
8
9
10
public class SimpleFactory {
public static PC createPC(String type){
if ("huawei".equals(type)){
return new HuaweiPc();
}else if("xiaomi".equals(type)){
return new XiaomiPc();
}
return null;
}
}

PCApp 类

1
2
3
4
5
6
7
8
public class PCApp {
public static void main(String[] args) {
PC xiaomiPC = SimpleFactory.createPC("xiaomi");
xiaomiPC.powerOn();
PC huaweiPC = SimpleFactory.createPC("huawei");
huaweiPC.powerOn();
}
}

优点

  • 封装了对象的创建过程,使得客户端不需要知道具体的创建细节
  • 客户端代码更加简洁,易于使用

缺点

  • 工厂类集中了所有产品的创建逻辑,一旦需要添加新的产品类型,可能需要修改工厂类,违反了开闭原则

为了解决简单工厂模式的缺点,可以对工厂类进行抽象,将不同产品的创建过程独立出来,由工厂子类决定实例化哪个类

工厂方法模式

和简单工厂模式中工厂负责生产所有产品相比,工厂方法模式将生成具体产品的任务分发给具体的产品工厂,其 UML 类图如下:

在这里插入图片描述

也就是定义一个抽象工厂,其定义了产品的生产接口,但不负责具体的产品,将生产任务交给不同的派生类工厂。这样不用通过指定类型来创建对象

AbstractFactory

1
2
3
public interface AbstractFactory {
PC createPc();
}

HuaweiPCFactory 类

1
2
3
4
5
6
public class HuaweiPCFactory implements AbstractFactory{
@Override
public PC createPc() {
return new HuaweiPc();
}
}

XiaomiPCFactory 类

1
2
3
4
5
6
public class XiaomiPCFactory implements AbstractFactory{
@Override
public PC createPc() {
return new XiaomiPc();
}
}

PCApp 类

1
2
3
4
5
6
7
8
public class PCApp {
public static void main(String[] args) {
PC huaweiPC = new HuaweiPCFactory().createPc();
huaweiPC.powerOn();
PC xiaomiPC = new XiaomiPCFactory().createPc();
xiaomiPC.powerOn();
}
}

优点

  • 使系统更具扩展性,可以方便地添加新的产品类和对应的工厂类
  • 遵循开闭原则,客户端代码不需要修改,只需要添加新的工厂和产品类

缺点

  • 类的数量较多,增加了系统的复杂性

上面两种模式不管工厂怎么拆分抽象,都只是针对一类产品 PC(AbstractProduct),如果要生成另一种产品 Phone,应该怎么表示呢?

最简单的方式是把 2 中介绍的工厂方法模式完全复制一份,不过这次生产的是 Phone。但同时也就意味着我们要完全复制和修改 PC 生产管理的所有代码,显然这是一个笨办法,并不利于扩展和维护。

抽象工厂模式

通过在 AbstarctFactory 中增加创建产品的接口,并在具体子工厂中实现新加产品的创建,当然前提是子工厂支持生产该产品。否则继承的这个接口可以什么也不干

在这里插入图片描述

从上面类图结构中可以清楚的看到如何在工厂方法模式中通过增加新产品接口来实现产品的增加

AbstractFactory 类

1
2
3
4
public interface AbstractFactory {
PC createPc();
Phone createPhone();
}

HuaweiFactory

1
2
3
4
5
6
7
8
9
10
11
public class HuaweiFactory implements AbstractFactory{
@Override
public PC createPc() {
return new HuaweiPc();
}

@Override
public Phone createPhone() {
return null;
}
}

XiaomiFactory

1
2
3
4
5
6
7
8
9
10
11
public class XiaomiFactory implements AbstractFactory{
@Override
public PC createPc() {
return new XiaomiPc();
}

@Override
public Phone createPhone() {
return new XiaomiPhone();
}
}

演示

1
2
3
4
5
6
7
8
public void testFactoryMethod2(){
PC huaweiPC = new HuaweiFactory().createPc();
huaweiPC.powerOn();
PC xiaomiPC = new XiaomiFactory().createPc();
xiaomiPC.powerOn();
Phone xiaomiPhone = new XiaomiFactory().createPhone();
xiaomiPhone.powerOn();
}

优点

  • 提供了一种创建一组相关对象的接口,避免了不同产品之间的兼容性问题
  • 客户端代码与具体产品类解耦,更容易替换产品系列

缺点

  • 新增产品类时,需要同时修改抽象工厂接口和所有的具体工厂类,不太符合开闭原则

对比

  • 关注点不同:
    • 简单工厂模式 关注于整个工厂的创建逻辑
    • 工厂方法模式 关注于单个产品的创建逻辑
    • 抽象工厂模式 关注于一组相关产品的创建逻辑
  • 抽象程度不同:
    • 简单工厂模式 抽象程度相对较低,只有一个工厂类
    • 工厂方法模式 在简单工厂模式的基础上提高了抽象程度,引入了工厂接口和具体工厂类
    • 抽象工厂模式 抽象程度更高,引入了多个抽象工厂接口和多个具体工厂类
  • 适用场景不同:
    • 简单工厂模式 适用于创建对象的逻辑较为简单的情况
    • 工厂方法模式 适用于创建对象的逻辑较为复杂,且可能有多个具体工厂类的情况
    • 抽象工厂模式 适用于创建一组相关或相互依赖对象的情况,且系统需要保持一定的产品系列