工厂模式

工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

工厂模式提供了一种将对象的实例化过程封装在工厂类中的方式。通过使用工厂模式,可以将对象的创建与使用代码分离,提供一种统一的接口来创建不同类型的对象。

在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

提供封装在工厂类中的静态方法,以隐藏对象初始化逻辑并使客户端代码专注于对象的使用而不是初始化。

解释

现实世界的例子:

想象一位炼金术士即将制造硬币。炼金术士必须能够制造金币和银币,并且必须能够在不修改现有源代码的情况下在它们之间进行切换。工厂模式通过提供静态构造方法来实现这一点,可以使用相关参数进行调用。

维基百科说:

工厂是一个用于创建其他对象的对象 - 正式而言,工厂是一个函数或方法,返回不同原型或类的对象。

代码示例:

我们有一个接口Coin和两个实现类GoldCoinSliverCoin

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
public interface Coin {

String getDescription();

}

public class GoldCoin implements Coin {

static final String DESCRIPTION = "这是金硬币!";

@Override
public String getDescription() {
return DESCRIPTION;
}

}

public class SliverCoin implements Coin {

static final String DESCRIPTION = "这是银硬币!";

@Override
public String getDescription() {
return DESCRIPTION;
}

}

下面的枚举代表我们支持的货币类型(GoldCoinSliverCoin)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public enum CoinType {

GOLD(GoldCoin::new),
SLIVER(SliverCoin::new);

private final Supplier<Coin> constructor;

CoinType(Supplier<Coin> constructor) {
this.constructor = constructor;
}

public Supplier<Coin> getConstructor() {
return constructor;
}

}

然后我们有封装了静态方法getCoin的工厂类CoinFactory来创建硬币对象。

1
2
3
4
5
6
7
public class CoinFactory {

public static Coin getCoin(CoinType coinType) {
return coinType.getConstructor().get();
}

}

现在,在客户端代码上,我们可以使用工厂类创建不同类型的硬币。

1
2
3
4
5
6
public static void main(String[] args) {
Coin goldCoin = CoinFactory.getCoin(CoinType.GOLD);
Coin sliverCoin = CoinFactory.getCoin(CoinType.SLIVER);
System.out.println(goldCoin.getDescription());
System.out.println(sliverCoin.getDescription());
}

程序输出:

1
2
这是金硬币!
这是银硬币!

随着需求的改变,现在炼金术士还必须能够制造铜币。我们只需要新增铜币的类CopperCoin并现实Coin接口。

1
2
3
4
5
6
7
8
9
public class CopperCoin implements Coin {

static final String DESCRIPTION = "这是铜硬币!";

@Override
public String getDescription() {
return DESCRIPTION;
}
}

然后在枚举类中新增铜币类型。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public enum CoinType {

GOLD(GoldCoin::new),
SLIVER(SliverCoin::new),
COPPER(copperCoin::new);

private final Supplier<Coin> constructor;

CoinType(Supplier<Coin> constructor) {
this.constructor = constructor;
}

public Supplier<Coin> getConstructor() {
return constructor;
}

}

现在我们可以直接调用工厂类的静态方法来创建铜币。

1
2
3
4
public static void main(String[] args) {
Coin copperCoin = CoinFactory.getCoin(CoinType.COPPER);
System.out.println(copperCoin.getDescription());
}

程序输出:

1
这是铜硬币!

适用性:

当您只关心对象的创建和使用,而不关心它如何创建和管理时,请使用工厂模式。

优点

  • 允许将所有对象创建保留在一处,并避免传播“新”对象跨代码库的关键字。
  • 允许编写松散耦合的代码。它的一些主要优点包括更好的可测试性、易于理解的代码、可交换的组件、可扩展性和独立的功能。

缺点

  • 代码变得比应有的更加复杂。

已知使用:

  • java.util.Calendar#getInstance()
  • java.util.ResourceBundle#getBundle()
  • java.text.NumberFormat#getInstance()
  • java.nio.charset.Charset#forName()
  • java.net.URLStreamHandlerFactory#createURLStreamHandler(String)(根据协议返回不同的单例对象)
  • java.util.EnumSet#of()
  • javax.xml.bind.JAXBContext#createMarshaller()以及其他类似的方法。