1.1概述
将一个复杂对象的构建与它的表示分离,使同样的构建过程可以创建不同的表示。这就是生产器模式的定义。
如果一个类中有若干个成员变量是其他类声明的对象,那么该类创建的对象就可以包含若干个其他对象作为其成员。习惯上把一个对象中的成员对象称作它的组件,例如,几何(Geometry)类含有三角形(Triangle)类、矩形(Rectangle)类和圆(Circle)类声明的对象,那么几何类就可以创建一个由三角形、矩形和圆形组成的几何图形,三角形、长方形和圆形就是当前几何图形中的组件。
但是,在编写几何类的构造方法的代码时可能会遇到如下困难:
(1) 有些用户并不需要几何类所创建对象含有的全部组件。
(2)有些用户对创建的几何类对象的组件有特殊要求,比如某用户要求其中的三角形是等边的,矩形是正方形等。
显然,如果一个对象由很多组件构成,我们无法在构造方法中进行硬编码来满足各种用户对组件结构的要求。因此,按着面向抽象的原则,我们不应该在几何类构造方法中进行任何编码,而是将几何类对象的构造方法分成若干个步骤,即根据当前组件的个数,在一个接口中定义若干个方法,每个方法负责创建几何类对象的一个组件,而实现该接口的类负责创建几何类对象,也就是说,将几何类对象的创建过程封装到另一个类中。
在设计模式中,封装一个对象的创建过程的类称作生成器,上述示例的示意图如下图一所示:(其中BuliderOne和BuliderTwo就是生成器)
图一:用生成器创建几何类对象
当系统准备为用户提供一个内部结构复杂的对象时,就可以使用生成器模式,使用该模式可以逐步地构造对象,使对象的创建更具弹性。生成器模式的关键是将一个含有多个组件对象的创建分成若干个步骤,并将这些步骤封装在一个称作生成器的接口中。
1.2模式的结构
生成器模式结构中包括四种角色:
(1)产品(Product):具体生产器要构造的复杂对象;
(2)抽象生成器(Bulider):抽象生成器是一个接口,该接口除了为创建一个Product对象的各个组件定义了若干个方法之外,还要定义返回Product对象的方法;
(3)具体生产器(ConcreteProduct):实现Builder接口的类,具体生成器将实现Builder接口所定义的方法;
(4)指挥者(Director):指挥者是一个类,该类需要含有Builder接口声明的变量。指挥者的职责是负责向用户提供具体生成器,即指挥者将请求具体生成器类来构造用户所需要的Product对象,如果所请求的具体生成器成功地构造出Product对象,指挥者就可以让该具体生产器返回所构造的Product对象。
生产器模式结构的类图如下图二所示:
图二:生成器模式结构类图
1.3生成器模式的优点
(1)生成器模式将对象的构造过程封装在具体生成器中,用户使用不同的具体生成器就可以得到该对象的不同表示。
(2)生成器模式将对象的构造过程从创建该对象的类中分离出来,是用户无须了解该对象的具体组件。
(3)可以更加精细有效地控制对象的构造过程。生成器将对象的构造过程分解成若干个步骤,这就使程序可以更加精细,有效地控制整个对象的构造。
(4)生成器模式将对象的构造过程与创建该对象类解耦,使对象的创建更加灵活有弹性。
(5)当增加新的具体生成器时,不必修改指挥者的代码,即该模式满足开-闭原则。
1.4适合使用生成器模式的情景
(1)当系统准备为用户提供一个内部结构复杂的对象,而且在构造方法中编写创建该对象的代码无法满足用户需求时,就可以使用生成器模式来构造这样的对象。
(2)当某些系统要求对象的构造过程必须独立于创建该对象的类时。
1.5生成器模式的使用
以下通过一个简单的问题来描述生成器模式中所涉及的各个角色。
这个简单的问题就是创建含有按钮、标签和文本框组件的容器。不同用户对容器有不同的要求,比如某些用户希望容器中只含有按钮和标签,某些用户希望容器中只含有按钮和文本框。另外,用户对组件在容器中的顺序位置也有不同的要求,比如某些用户要求组件在容器中从左至右的排列顺序是按钮、标签、文本框,而某些用户要求从左到右的排列顺序是标签、文本框、按钮等。
显然不能在容器的构造方法中编写有关创建按钮、标签和文本框的代码,也不能编写排列这些组件位置的代码。以下使用生成器为用户创建所需要的容器,具体如下:
首先看一下本实例构建框架具体类和1.2模式的结构中类图的对应关系,如下图所示:
(1)产品(Product)
产品角色是PanelProduct类,该类代码如下:
package com.liuzhen.twelve_builder;
import javax.swing.*;
@SuppressWarnings("serial")
public class PanelProduct extends JPanel{
JButton button;
JLabel label;
JTextField textField;
}
(2)抽象生成器(Builder)
抽象生成器是Builder接口,其代码如下:
package com.liuzhen.twelve_builder;
import javax.swing.JPanel;
public interface Builder {
public abstract void buildButton();
public abstract void buildLabel();
public abstract void buildTextField();
public abstract JPanel getPanel();
}
(3)具体生成器(ConcreteBuilder)
有两个具体生成器类ConcreteBuilderOne和ConcreteBuilderTwo,具体代码如下:
ConcreteBuilderOne.java
package com.liuzhen.twelve_builder;
import javax.swing.*;
public class ConcreteBuilderOne implements Builder {
private PanelProduct panel;
ConcreteBuilderOne(){
panel = new PanelProduct();
}
public void buildButton() {
// TODO Auto-generated method stub
panel.button = new JButton("按钮");
}
public void buildLabel() {
// TODO Auto-generated method stub
panel.label = new JLabel("标签");
}
public void buildTextField() {
// TODO Auto-generated method stub
panel.textField = new JTextField("文本框");
}
public JPanel getPanel() {
// TODO Auto-generated method stub
panel.add(panel.button); //与ConcreteBuilderTwo添加组件的顺序不同
panel.add(panel.label);
panel.add(panel.textField);
return panel;
}
}
ConcreteBuilderTwo.java
package com.liuzhen.twelve_builder;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class ConcreteBuilderTwo implements Builder {
private PanelProduct panel;
ConcreteBuilderTwo(){
panel = new PanelProduct();
}
public void buildButton() {
// TODO Auto-generated method stub
panel.button = new JButton("按钮");
}
public void buildLabel() {
// TODO Auto-generated method stub
panel.label = new JLabel("标签");
}
public void buildTextField() {
// TODO Auto-generated method stub
panel.textField = new JTextField("文本框");
}
public JPanel getPanel() {
// TODO Auto-generated method stub
panel.add(panel.textField); //与ConcreteBuilderOne添加组件的顺序不同
panel.add(panel.label);
panel.add(panel.button);
return panel;
}
}
(4)指挥者(Director)
指挥者是Director类,其代码如下:
package com.liuzhen.twelve_builder;
import javax.swing.JPanel;
public class Director {
private Builder builder;
Director(Builder builder){
this.builder = builder;
}
public JPanel constructProduct(){
builder.buildButton();
builder.buildLabel();
builder.buildTextField();
JPanel product = builder.getPanel();
return product;
}
}
(5)具体使用
通过TwelveApplication类来具体实现上述相关类,来实现工厂方法模式的运用,其代码如下:
package com.liuzhen.twelve_builder;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class TwelveApplication {
public static void main(String[] args) {
Builder builder = new ConcreteBuilderOne();
Director director = new Director(builder);
JPanel panel = director.constructProduct();
JFrame frameOne = new JFrame();
frameOne.add(panel);
frameOne.setBounds(12, 12, 200, 120);
frameOne.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frameOne.setVisible(true);
builder = new ConcreteBuilderTwo();
director = new Director(builder);
panel = director.constructProduct();
JFrame frameTwo = new JFrame();
frameTwo.add(panel);
frameTwo.setBounds(12, 12, 200, 120);
frameTwo.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frameTwo.setVisible(true);
}
}
运行结果:
参考资料:
1.Java设计模式/耿祥义,张跃平著.——北京:清华大学出版社,2009.5