【创建型模式】建造者模式

时间:2024-04-20 18:15:16

一、建造者模式概述

        建造者模式定义将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同得表示。(对象创建型模式)

  • 建造者模式分析
    • 1.将客户端与包含多个部件得复杂对象得创建过程分离,客户端无需知道复杂对象得内部组成部分与装配方式,只需要知道所需建造者得类型即可;
    • 2.关注如何逐步创建一个复杂得对象,不同得建造者定义了不同得创建过程。
  • 建造者模式的优缺点
    • 优点
      • 1.客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象;
        • 2.每一个具体建造者都相对独立,与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者,扩展方便,符合开闭原则;
      • 3.可以更加精细地控制产品的创建过程。
    • 缺点
      • 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());
		}
	}
}
        2.8 UML图

三、代码结构图