设计模式之工厂模式的 Java 实现

工厂模式 属于设计模式中创建型数据模式的一种,同时是软件设计模式中最常使用的模式。广义的工厂模式只是一个统称,其还可以继续分为 简单工厂模式工厂模式抽象工厂模式。这里对这些工厂模式进行说明并使用 Java 代码进行实现。

通常状态下的对象创建

在不使用任何模式的时候,我们通常是需要什么对象,就直接创建什么对象,如下所示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/* Bicycle.java */
public class Bicycle {
public Bicycle() {
System.out.println(this.getClass().getSimpleName());
}
}

/* Motorbike.java */
public class Motorbike {
public Motorbike() {
System.out.println(this.getClass().getSimpleName());
}
}

/* Main.java */
public class Main {
public static void main(String[] args) {
Bicycle bicycle = new Bicycle();
Motorbike motorbike = new Motorbike();
}
}
Bicycle
Motorbike

这很符合面向对象的思想,通过使用 new 操作符去构造对象实例,但是如果我们需要在实例化时做点初始化的工作呢?我们可以去使用构造方法,但是假如要做的事情很多,代码很长呢?或是我们在创建需要的对象之前必须先生成一些辅助功能的对象,我们就可以使用工厂模式来生成对象,而不用去关心构造对象实例的细节和其复杂的过程。

简单工厂模式

定义

简单工厂模式 (Simple Factory Pattern) 又称为静态工厂方法 (Static Factory Method) 模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

适用环境

在以下情况下可以使用简单工厂模式:

  • 工厂类负责创建的对象比较少;由于创建的对象较少,不会造成工厂方法中的业务逻辑太过复杂。
  • 客户端只知道传入工厂类的参数,对于如何创建对象不关心;客户端既不需要关心创建细节,甚至连类名都不需要记住,只需要知道类型所对应的参数。

模式结构

举例

假如这里有一个农场充当工厂类,通过告知农场所需要的水果类型返回所需的水果,即通过传入不同的参数获取不同的对象。

对象类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* Fruit.java */
public abstract class Fruit {
}

/* Apple.java */
public class Apple extends Fruit {
public Apple() {
System.out.println(this.getClass().getSimpleName());
}
}

/* Banana.java */
public class Banana extends Fruit {
public Banana() {
System.out.println(this.getClass().getSimpleName());
}
}

/* Orange.java */
public class Orange extends Fruit {
public Orange() {
System.out.println(this.getClass().getSimpleName());
}
}

工厂类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/* FarmFactory.java */
public class FarmFactory {
public Fruit get(String variety) {
switch (variety) {
case "apple":
return new Apple();
case "banana":
return new Banana();
case "orange":
return new Orange();
default:
return null;
}
}
}

调用方式:

1
2
3
4
5
6
7
8
9
/* Main.java */
public class Main {
public static void main(String[] args) {
FarmFactory farmFactory = new FarmFactory();
Fruit apple = farmFactory.get("apple");
Fruit banana = farmFactory.get("banana");
Fruit orange = farmFactory.get("orange");
}
}

输出:

Apple
Banana
Orange

工厂模式

模式动机

接上面的例子,假如现在农场新种植了一种水果,那么为了完成工厂类的任务,就需要去修改工厂类的代码添加内部逻辑,这显然是违背开闭原则的。

所谓开闭原则,就是对扩展开放,对修改关闭。“开”是指对于组件功能的扩展是开放的,是允许对其进行功能扩展的,“闭”是对原有代码的修改是封闭的,即修改原有的代码对外部的使用是透明的。即对模块行为进行扩展时,不必改动模块的源代码或者二进制代码,所以就出现了工厂模式。

参见:http://baike.baidu.com/item/开闭原则

现假如有一个生产各种按钮的工厂,通过对该系统进行修改,不再设计一个按钮工厂类来统一负责所有产品的创建,而是将具体按钮的创建过程交给专门的工厂子类去完成,我们先定义一个抽象的按钮工厂类,再定义具体的工厂类来生成圆形按钮、矩形按钮、菱形按钮等,它们实现在在抽象按钮工厂中定义的方法。这种抽象化的结果使这种结构可以在不修改具体工厂类的情况下引进新的产品,如果出现新的按钮类型,只需要为这种新类型的按钮创建一个具体的工厂类就可以获得该新按钮的实例,这一特点无疑使得工厂方法模式具有超越简单工厂模式的优越性,更加符合“开闭原则”。

定义

工厂方法模式 (Factory Method Pattern) 又称为工厂模式,也叫虚拟构造器 (Virtual Constructor) 模式或者多态工厂 (Polymorphic Factory) 模式,它属于类创建型模式。在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象,这样做的目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪—个具体产品类。

模式结构

举例

对上面的按钮工厂的工厂模式实现。

对象类:

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
/* Button.java */
public abstract class Button {
}

/* CircleButton.java */
public class CircleButton extends Button {

public CircleButton() {
System.out.println(this.getClass().getSimpleName());
}
}

/* DiamondButton.java */
public class DiamondButton extends Button {

public DiamondButton() {
System.out.println(this.getClass().getSimpleName());
}
}

/* RectangleButton.java */
public class RectangleButton extends Button {

public RectangleButton() {
System.out.println(this.getClass().getSimpleName());
}
}

工厂类:

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
/* FarmFactory.java */
public abstract class ButtonFactory {

public abstract Button create();
}

/* CircleButtonFactory.java */
public class CircleButtonFactory extends ButtonFactory {
@Override
public Button create() {
return new CircleButton();
}
}

/* DiamondButtonFactory.java */
public class DiamondButtonFactory extends ButtonFactory {
@Override
public Button create() {
return new DiamondButton();
}
}

/* RectangleButtonFactory.java */
public class RectangleButtonFactory extends ButtonFactory {
@Override
public Button create() {
return new RectangleButton();
}
}

调用方式:

1
2
3
4
5
6
7
8
9
/* Main.java */
public class Main {
public static void main(String[] args) {
ButtonFactory buttonFactory = new CircleButtonFactory();
Button button = buttonFactory.create();
buttonFactory = new DiamondButtonFactory();
button = buttonFactory.create();
}
}

输出:

CircleButton
DiamondButton

抽象工厂模式

模式动机

在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法也具有唯一性,一般情况下,一个具体工厂中只有一个工厂方法或者一组重栽的工厂方法。但是有时候我们需要一个工厂可以提供多个产品对象,而不是单一的产品对象。

为了更清晰地理解工厂方法糢式,需要先引入两个概念:

  • 产品等级结构:产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了—个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。
  • 产品族:在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中。

定义

抽象工厂模式 (Abstract Factory Pattern) 提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为 Kit 模式,属于对象创建型模式。

应用场景

  • 当系统所提供的工厂生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构、属于不同类型的具体产品时就可以使用抽象工厂模式。
  • 抽象工厂模式是所有形式的工厂模式中最为抽象和最具一般性的一种形式。

模式适用环境

  • 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节。
  • 系统中有多于一个的产品族,但每次只使用其中某一产品族。
  • 属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。
  • 产品等级结构稳定,设计完成之后,不会向系统中增加新的产品等级结构或者删除已有的产品等级结构。

模式结构

举例

某软件公司要开发一套界面皮肤库,可以对基于 .NET 平台的桌面软件进行界面美化。用户在使用时可以通过菜单来选择皮肤,不同的皮肤将提供视觉效果不同的按钮、文本框、组合框等界面元素,例如春天 (Spring) 风格的皮肤将提供浅绿色的按钮、绿色边框的文本框和绿色边框的组合框,而夏天 (Summer) 风格的皮肤则提供浅蓝色的按钮、蓝色边框的文本框和蓝色边框的组合框,其结构示意图如下图所示:

该皮肤库需要具备良好的灵活性和可扩展性,用户可以自由选择不同的皮肤,开发人员可以在不修改既有代码的基础上增加新的皮肤,现使用抽象工厂模式来设计该界面皮肤库。

对象类:

  • ComboBox
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/* ComboBox.java */
public abstract class ComboBox {
}

/* SummerComboBox.java */
public class SummerComboBox extends ComboBox {
public SummerComboBox() {
System.out.println(this.getClass().getSimpleName());
}
}

/* SpringComboBox.java */
public class SpringComboBox extends ComboBox {
public SpringComboBox() {
System.out.println(this.getClass().getSimpleName());
}
}
  • Button
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/* Button.java */
public abstract class Button {
}

/* SummerButton.java */
public class SummerButton extends Button{
public SummerButton() {
System.out.println(this.getClass().getSimpleName());
}
}

/* SpringButton.java */
public class SpringButton extends Button {
public SpringButton() {
System.out.println(this.getClass().getSimpleName());
}
}
  • TextField
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/* TextField.java */
public abstract class TextField {
}

/* SummerTextField.java */
public class SummerTextField extends TextField {
public SummerTextField() {
System.out.println(this.getClass().getSimpleName());
}
}

/* SpringTextField.java */
public class SpringTextField extends TextField {
public SpringTextField() {
System.out.println(this.getClass().getSimpleName());
}
}

工厂类:

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
/* SkinFactory.java */
public abstract class SkinFactory {
public abstract ComboBox getComboBox();
public abstract Button getButton();
public abstract TextField getTextField();
}

/* SummerSkinFactory.java */
public class SummerSkinFactory extends SkinFactory {
@Override
public ComboBox getComboBox() {
return new SummerComboBox();
}
@Override
public Button getButton() {
return new SummerButton();
}
@Override
public TextField getTextField() {
return new SummerTextField();
}
}

/* SpringSkinFactory.java */
public class SpringSkinFactory extends SkinFactory {
@Override
public ComboBox getComboBox() {
return new SpringComboBox();
}
@Override
public Button getButton() {
return new SpringButton();
}
@Override
public TextField getTextField() {
return new SpringTextField();
}
}

调用方式:

1
2
3
4
5
6
7
8
9
/* Main.java */
public class Main {
public static void main(String[] args) {
SkinFactory skinFactory = new SummerSkinFactory();
ComboBox comboBox = skinFactory.getComboBox();
Button button = skinFactory.getButton();
TextField textField = skinFactory.getTextField();
}
}

输出:

SummerComboBox
SummerButton
SummerTextField