工厂方法模式
简单工厂模式
阅读前,建议先了解简单工厂模式,请点击这里。
介绍
工厂方法模式是类的创建型模式,又叫虚拟构造器(Vitual Constructor)模式或者多态性工厂(Polymorphic Factory)模式。工厂方法模式的用意是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类中。
简单工厂模式的缺点
在简单工厂模式中,当新增产品时,无需修改抽象产品源码就能新增产品,但是需要修改工厂源代码,所以简单工厂只在有限的程度上支持“开-闭”原则。
工厂方法模式的引进
由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,克服了它的缺点。
首先,在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建的工作交给子类去做。这个核心类则摇身一变,成为了一个抽象工厂角色,仅负责给出具体工厂子类必须实现的接口,而不接触哪一个产品应当被实例化的细节。
这种进一步抽象化的结果,使这种工厂方法模式可以用来允许系统在不修改具体工厂角色的情况下引进新的产品,这一特点无疑使得工厂模式具有超过简单工厂模式的优越性。
模式角色
工厂方法模式有以下角色:
- Creator(抽象工厂类),是工厂方法模式的核心,与应用程序无关。任何在模式中创建的对象的工厂类必须实现这个接口。
- ConcreteCreator(具体工厂类),这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建产品对象。
- Product(抽象产品),工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。
- ConcreteProduct(抽象工厂类),这个角色实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂创建,它们之间往往一一对应。
模式结构图
模式实现
模式实现,下面通过伪代码去实现该模式:
模拟移动端的View框架或者说需要写一个有多端风格的GUI框架(Android风格、iOS风格),这个系统有显示文本的TextView控件,显示一个按钮的Button控件,显示一个列表、一个圆…
/**
* 工厂方法模式
*/
public abstract class FactoryMethod {
public abstract FactoryMethodView factory();
}
/**
* 具体工厂
* Android风格-TextView的具体工厂类
*/
class AndroidTextViewFactoryMethod extends FactoryMethod {
@Override
public FactoryMethodView factory() {
return new FactoryMethodAndroidTextView();
}
}
/**
* 具体工厂
* iOS风格-TextView的具体工厂类
*/
class IOSTextViewFactoryMethod extends FactoryMethod {
@Override
public FactoryMethodView factory() {
return new FactoryMethodIOSTextView();
}
}
/**
* 抽象产品
* 控件基类-View
*/
abstract class FactoryMethodView {
private int width;
private int height;
public FactoryMethodView() {
}
public FactoryMethodView(int width, int height) {
this.width = width;
this.height = height;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
public abstract void onDraw();
}
/**
* 具体产品
* Android风格-TextView
*/
class FactoryMethodAndroidTextView extends FactoryMethodView {
// 显示的文本
private String text;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
@Override
public void onDraw() {
System.out.println("绘制文本");
}
}
/**
* 具体产品
* iOS风格-TextView
*/
class FactoryMethodIOSTextView extends FactoryMethodView {
// 显示的文本
private String text;
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
@Override
public void onDraw() {
System.out.println("绘制文本");
}
}
/**
* client
*/
class FactoryMethodClient {
public static void main(String[] args) throws BadSimpleFactoryViewException {
FactoryMethod factory = null;
FactoryMethodView view = null;
// AndroidTextView
factory = new AndroidTextViewFactoryMethod();
view = factory.factory();
view.onDraw();
// iOSTextView
factory = new IOSTextViewFactoryMethod();
view = factory.factory();
view.onDraw();
}
}
工厂等级结构与产品等级结构平行
使用Java接口或者Java抽象类
模式多个工厂方法
抽象工厂角色可以规定出多于一个的工厂方法,从而使具体工厂角色实现这些不同工厂方法。
产品对象的循环使用和登记式的工厂方法
在很多情况下,产品对象可以循环使用。换言之工厂方法可以循环使用已经创建出来的对象,而不是每一次都创建新的对象。工厂方法可以通过登记它所创建的产品对象来达到循环使用产品对象的目的。
多态性的丧失和模式的退化
模式的优点和缺点
优点:
- 符合开-闭原则,新增一种产品时,只需要增加相应的具体产品类和相应的工厂子类即可。
- 符合单一职责原则,每个具体工厂类只负责创建对应的产品。
- 不使用静态工厂方法,可以形成基于继承的等级结构。
缺点:
- 添加新产品时,除了增加新产品类外,还要提供与之对应的具体工厂类,系统类的个数将成对增加,在一定程度上增加了系统的复杂度;同时,有更多的类需要编译和运行,会给系统带来一些额外的开销。
- 由于系统的可扩展性,在客户端中要引入抽象层进行定义,从而增加了系统的抽象性和理解难度。
模式应用
- 对于某个产品,调用者清楚地知道应该使用哪个具体工厂服务,实例化该具体工厂,生产出具体的产品来。Java Collection中的iterator() 方法即属于这种情况。
- 只是需要一种产品,而不想知道也不需要知道究竟是哪个工厂为生产的,即最终选用哪个具体工厂的决定权在生产者一方,它们根据当前系统的情况来实例化一个具体的工厂返回给使用者,而这个决策过程这对于使用者来说是透明的。