一、建造者模式概述
建造者模式定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同得表示。(对象创建型模式)。
-
建造者模式分析:
- 1.将客户端与包含多个部件得复杂对象得创建过程分离,客户端无需知道复杂对象得内部组成部分与装配方式,只需要知道所需建造者得类型即可;
- 2.关注如何逐步创建一个复杂得对象,不同得建造者定义了不同得创建过程。
-
建造者模式的优缺点:
-
优点:
- 1.客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象;
- 2.每一个具体建造者都相对独立,与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者,扩展方便,符合开闭原则;
- 3.可以更加精细地控制产品的创建过程。
- 1.客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象;
-
缺点:
- 1.建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,不适合使用建造者模式,因此其使用范围受到一定的限制;
- 2.如果产品的内部变化复杂,可能会需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大,增加了系统的理解难度和运行成本
-
优点:
-
适用环境:
- 1.需要生成的产品对象有复杂的内部结构,这些产品对象通常包含多个成员变量;
- 2.需要生成的产品对象的属性相互依赖,需要指定其生成顺序;
- 3.对象的创建过程独立于创建该对象的类。在建造者模式中通过引入了指挥者类,将创建过程封装在指挥者类中,而不在建造者类和客户类中;
- 4.隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。
二、代码实现
建造者模式包含四个角色:
- 抽象建造者: 创建一个Product 对象的各个部件指定的接口/抽象类;
- 具体建造者: 实现接口,构建和装配各个部件;
- 产品:一个具体的产品对象;
-
指挥者:构建一个使用Builder 接口的对象。它主要是用于创建一个复杂的对象。它主要有两个作用:
- 1.隔离了客户与对象的生产过程;
- 2.负责控制产品对象的生产过程。
其中,对于指挥者类有一些深入讨论:
- 1 省略Director:将construct()方法中的参数去掉,直接在construct()方法中调用buildPartX()方法;
- 2 钩子方法的引入:钩子方法(Hook Method):返回类型通常为boolean类型,方法名一般为isXXX()。
2.1 抽象建造者(Decorator)
package builder.livingdecorator;
//抽象建造者
public abstract class Decorator {
// 创建产品对象
protected Parlour product = new Parlour();
public abstract void buildWall();
public abstract void buildTV();
public abstract void buildSofa();
// 返回产品对象
public Parlour getResult() {
return product;
}
}
2.2 具体建造者(ConcreteDecorator1、ConcreteDecorator2)
package builder.livingdecorator;
//具体建造者:具体装修工人1
public class ConcreteDecorator1 extends Decorator {
@Override
public void buildWall() {
// TODO Auto-generated method stub
product.setWall("w1");
}
@Override
public void buildTV() {
// TODO Auto-generated method stub
product.setTV("TV1");
}
@Override
public void buildSofa() {
// TODO Auto-generated method stub
product.setSofa("sf1");
}
}
package builder.livingdecorator;
//具体建造者:具体装修工人2
public class ConcreteDecorator2 extends Decorator {
@Override
public void buildWall() {
// TODO Auto-generated method stub
product.setWall("w2");
}
@Override
public void buildTV() {
// TODO Auto-generated method stub
product.setTV("TV2");
}
@Override
public void buildSofa() {
// TODO Auto-generated method stub
product.setSofa("sf2");
}
}
2.3 产品(Parlour)
package builder.livingdecorator;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;
import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
//产品:客厅
public class Parlour {
private String wall; // 墙
private String TV; // 电视
private String sofa; // 沙发
public void setWall(String wall) {
this.wall = wall;
}
public void setTV(String TV) {
this.TV = TV;
}
public void setSofa(String sofa) {
this.sofa = sofa;
}
public void show() {
JFrame jf = new JFrame("建造者模式测试");
Container contentPane = jf.getContentPane();
JPanel p = new JPanel();
JScrollPane sp = new JScrollPane(p);
String parlour = wall + TV + sofa;
String picture = "src/builder/livingdecorator/" + parlour + ".jpg";
//String picture = "src/structural_patterns/builder/decorator/" +name ;
JLabel l = new JLabel(new ImageIcon(picture));
p.setLayout(new GridLayout(1, 1));
p.setBorder(BorderFactory.createTitledBorder("客厅"));
p.add(l);
contentPane.add(sp, BorderLayout.CENTER);
jf.pack();
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
2.4 指挥者(ProjectManager)
package builder.livingdecorator;
//指挥者:项目经理
public class ProjectManager {
private Decorator builder;
public ProjectManager(Decorator builder) {
this.builder = builder;
}
// 产品构建与组装方法
public Parlour decorate() {
builder.buildWall();
builder.buildTV();
builder.buildSofa();
return builder.getResult();
}
}
2.5 实例化工具代码(ReadXML)
package builder.livingdecorator;
import javax.xml.parsers.*;
import org.w3c.dom.*;
import java.io.*;
public class ReadXML
{
public static Object getObject()
{
try
{
DocumentBuilderFactory dFactory=DocumentBuilderFactory.newInstance();
DocumentBuilder builder=dFactory.newDocumentBuilder();
Document doc;
doc=builder.parse(new File("src/builder/livingdecorator/config.xml"));
NodeList nl=doc.getElementsByTagName("className");
Node classNode=nl.item(0).getFirstChild();
String cName=classNode.getNodeValue();
System.out.println("新类名:"+cName);
Class<?> c=Class.forName(cName);
Object obj=c.newInstance();
return obj;
}
catch(Exception e)
{
e.printStackTrace();
return null;
}
}
}
2.6 配置文件(config.xml)
<?xml version="1.0"?>
<config>
<className>builder.livingdecorator.ConcreteDecorator1</className>
</config>
2.7 main方法实现建造者模式
package builder.livingdecorator;
import java.awt.*;
import javax.swing.*;
public class ParlourDecoratorClient {
public static void main(String[] args) {
try {
//Decorator d=new ConcreteDecorator2();
Decorator d=(Decorator) ReadXML.getObject();
ProjectManager m=new ProjectManager(d);
Parlour p=m.decorate();
p.show();
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}