一、建造者模式概述
建造者模式定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同得表示。(对象创建型模式)。
- 建造者模式分析:
- 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 {@Overridepublic void buildWall() {// TODO Auto-generated method stubproduct.setWall("w1");}@Overridepublic void buildTV() {// TODO Auto-generated method stubproduct.setTV("TV1");}@Overridepublic void buildSofa() {// TODO Auto-generated method stubproduct.setSofa("sf1");}}
package builder.livingdecorator;
//具体建造者:具体装修工人2
public class ConcreteDecorator2 extends Decorator {@Overridepublic void buildWall() {// TODO Auto-generated method stubproduct.setWall("w2");}@Overridepublic void buildTV() {// TODO Auto-generated method stubproduct.setTV("TV2");}@Overridepublic void buildSofa() {// TODO Auto-generated method stubproduct.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());}}
}