设计模式(4):工厂方法FACTORY METHOD

工厂方法

工厂方法(Factory Method)也称虚构造器(Virtual Constructor)

意图

定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。

适用性

Use the Factory Method pattern when

  • a class can’t anticipate the class of objects it must create.(一个类不知道它所需要的对象的类,也就是说,不需要知道具体产品的类名,只需要知道创建它的具体工厂就行了)
  • a class wants its subclasses to specify the objects it creates.(一个类通过子类来指定所要创建的对象,抽象工厂类只提供创建产品的接口,由子类来确定要创建的具体的对象,充分利用多态的特性,运行时子类对象替换父类对象)
  • classes delegate responsibility to one of several helper subclasses, and you want to localize the knowledge of which helper subclass is the delegate.(将创建对象的任务委托给多个工厂子类中的一个,这样使用时就不用关心到底是哪一个工厂子类创建产品子类,需要的时候动态指定就可以了)

结构

工厂方法的结构如下图
ShowImage

  • Product

    – 定义工厂方法所创建的对象所提供的接口(或者抽象类)。

  • ConcreteProduct

    – 实现Product的接口(或者抽象类)。

  • Creator

    – 声明工厂方法,该方法返回一个Product类型的对象。Creator也可以定义一个工厂方法的缺省实现,它返回一个缺省的ConcreteCreator对象。

    – 可以调用工厂方法以创建一个Product对象。

  • ConcreteCreator

    – 表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程。

    – 重写(Override)工厂方法以返回一个ConcreteProduct实例。

工厂方法模式实现(Implement)

案例

现在用经典的shape,circle,square例子来说明工厂方法的实现。
首先定义一个Product,Shape类,Shape有自己的名字name,还有抽象方法draw()绘制图形,代码如下

1
2
3
4
5
6
7
8
9
public abstract class Shape {
public String name;
public Shape(String name) {
this.name = name;
}
public abstract void draw();
}

现在有两个ConcreteProduct,分别是Circle类和Square类,代码如下

1
2
3
4
5
6
7
8
9
10
public class Circle extends Shape {
@Override
public void draw() {
System.out.println("Draw a circle..." + name);
}
public Circle(String name) {
super(name);
}
}

1
2
3
4
5
6
7
8
9
10
public class Square extends Shape {
@Override
public void draw() {
System.out.println("Draw a square..." + name);
}
public Square(String name) {
super(name);
}
}

接下来我们定义一个Creator,ShapeFactory类,代码如下

1
2
3
public abstract class ShapeFactory {
protected abstract Shape createShape(String name);
}

要生成这两个产品,现在得将Creator生成产品的工作委托给它的子类ConcreteCreator去执行,定义CircleFactory类和SquareFactory类

1
2
3
4
5
6
public class CircleFactory extends ShapeFactory {
@Override
protected Shape createShape(String name) {
return new Circle(name);
}
}

1
2
3
4
5
6
public class SquareFactory extends ShapeFactory {
@Override
protected Shape createShape(String name) {
return new Square(name);
}
}

最后,我们的Client来使用工厂方法创建我们需要的对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class FactoryMethodTest {
@Test
public void factoryMethodTest() {
ShapeFactory squareFactory = new SquareFactory();
ShapeFactory circleFactory = new CircleFactory();
Shape square1 = squareFactory.createShape("square1");
Shape square2 = squareFactory.createShape("square2");
Shape circle1 = circleFactory.createShape("circle1");
Shape circle2 = circleFactory.createShape("circle2");
square1.draw();
square2.draw();
circle1.draw();
circle2.draw();
}
}

得到的输出结果为

1
2
3
4
Draw a square...square1
Draw a square...square2
Draw a circle...circle1
Draw a circle...circle2

可以看到我们的Client并不需要知道要创造产品的细节甚至产品名,它们都是Shape类型,由工厂方法创建出来,但是在执行的时候会去执行子类中重写的draw方法。

总结

本文对工厂方法进行了简单的介绍,可以得出工厂方法有以下几个优点

  • 良好的封装性,类之间的耦合性降低,调用者需要创建一个具体的产品的对象时,只需要去找到对应的工厂方法就可以了,不用去了解详细的对象初始化过程。调用者与产品类之间完全解耦,产品类的实现变化时,调用者都不关心,调用者只关心抽象类的接口,符合迪米特法则。
  • 优秀的扩展性,符合开闭原则,需要增加产品类时,只需要在原有的基础上增加新实现的具体工厂类即可,不用去修改原有代码的实现。
  • 利用多态特性,符合里氏替换原则,子类可以替换父类
  • 符合依赖倒置原则,只依赖了产品的接口(或者抽象类)而不依赖具体的实现

参考代码

------ 本文结束 ------

版权声明


BillyYccc's blog by Billy Yuan is licensed under a Creative Commons BY-NC-SA 4.0 International License.
本文原创于BillyYccc's Blog,转载请注明原作者及出处!