目录
建造者模式
本质: 分离整体构建算法和部件构造
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
创建过程是稳定的
UML图
过程:客户把具体建造者对象交给指导者,指导者操纵具体建造者创建产品。产品创建完成后,具体建造者把产品返还给客户端
建造者(Builder)角色:
定义创建一个Product对象所需各个操作的方法+一个返回Product对象的方法
具体建造者(Concrete Builder)角色:
实现Builder中的方法,完成创建产品实例的过程+提供产品的实例。
指导者(Director)角色:(核心)
使用Builder中的方法,以一个统一的过程来构建所需要的Product对象
产品(Product)角色:
需要建造的复杂对象。
客户端:
创建指导者和具体建造者的对象。
示例代码
public class Director {
public void Construct(Builder builder){
builder.BuildPartA();
builder.BuildPartB();
}
}
public abstract class Builder {
//产品由两个组件A、B组成(A、B是抽象的,还不确定)
public abstract void BuildPartA();
public abstract void BuildPartB();
//得到产品建造结果
public abstract Product getResult();
}
public class ConcreteBuilder1 extends Builder{
private Product product=new Product();
@Override
public void BuildPartA() {
System.out.println("部件a");
}
@Override
public void BuildPartB() {
System.out.println("部件b");
}
@Override
public Product getResult() {
return product;
}
}
public class ConcreteBuilder2 extends Builder{
private Product product=new Product();
@Override
public void BuildPartA() {
System.out.println("部件X");
}
@Override
public void BuildPartB() {
System.out.println("部件Y");
}
@Override
public Product getResult() {
return product;
}
}
import java.util.ArrayList;
public class Product {
ArrayList<String> parts=new ArrayList<String>();
public void Add(String part){
parts.add(part);
}
public void show(){
System.out.println("产品创建");
for(String part:parts){
System.out.println(part);
}
}
}
public class Main {
public static void main(String[] args) {
Director director=new Director();
Builder b1=new ConcreteBuilder1();
Builder b2=new ConcreteBuilder2();
director.Construct(b1);
Product p1=b1.getResult();
p1.show();
director.Construct(b2);
Product p2=b2.getResult();
p2.show();
}
}
适用场景
- 需要生成的产品对象有复杂的内部结构。
- 需要生成的产品对象的属性相互依赖,建造者模式可以强迫指定其生成顺序。
- 在对象创建过程中会使用到系统中的一些其它对象,这些对象在产品对象的创建过程中不易得到。
优缺点
优点:
- 产品的内部组成可独立的变化
- 客户端不必知道产品内部组成的细节
- 扩展性好:具体建造类相互独立
- 将复杂的产品创建过程分解,更方便控制创建过程
缺点:
-
适用范围受限:要求创建的产品具有较多的共同点,其组成部分相似。如果产品之间的差异性很大,如组成部分很多不同,则不适合用建造者模式。
-
如果产品内部变化复杂,可能需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大,增加了系统的理解难度和运行成本
建造者模式VS工厂方法模式 :
- 注重点不同:建造者模式注重于方法的调用顺序;工厂模式注重创建产品对象
- 创建对象力度不同:建造者模式可以创建复杂的产品;工厂模式创建出来的都是相同的实例对象。
实例——导出文件
导出数据的应用框架,通常对于具体的导出内容和格式是有要求的:
分成三部分,文件头、文件体、文件尾
- 文件头:分公司编号、导出数据的日期,对于文本格式,中间用逗号分离
- 文件体:表名称,然后分条描述数据
- 文件尾:输出人
不管是输出文本文件,还是输出XML文件,步骤基本一致
- 先拼接文件头的内容
- 然后拼接文件体的内容
- 再拼接文件尾的内容
最后把拼接好的内容输出去成为文件
public class Director {
public void constract(FileBuilder fb) {
fb.fileHead();
fb.fileBody();
fb.fileTail();
fb.getResult();
}
}
import java.util.Date;
public abstract class FileBuilder {
protected String no;//分公司编号
protected Date date;// 导出日期
protected String tablename;//表名
protected String username;//输出人
public abstract void fileHead();
public abstract void fileBody();
public abstract void fileTail();
public abstract void getResult();
public FileBuilder(String no, Date date, String tablename, String username) {
this.no = no;
this.date = date;
this.tablename = tablename;
this.username = username;
}
}
import java.util.Date;
public class TextFileBuilder extends FileBuilder{
public TextFileBuilder(String no, Date date, String tablename, String username) {
super(no, date, tablename, username);
// TODO Auto-generated constructor stub
}
@Override
public void fileHead() {
System.out.println("导出数据为文本文件");
System.out.println("文本文件头:");
System.out.println("分公司编号:"+no);
System.out.println("导出日期:"+date);
}
@Override
public void fileBody() {
System.out.println("文本文件体:");
System.out.println("表名:"+tablename);
}
@Override
public void fileTail() {
System.out.println("文本文件尾:");
System.out.println("输出人:"+username);
}
@Override
public void getResult() {
System.out.println("已导出完毕");
}
}
package com.data;
import java.util.Date;
public class XmlFileBuilder extends FileBuilder{
public XmlFileBuilder(String no, Date date, String tablename, String username) {
super(no, date, tablename, username);
// TODO Auto-generated constructor stub
}
@Override
public void fileHead() {
System.out.println("导出数据为XML文件");
System.out.println("文本文件头:");
System.out.println("分公司编号:"+no);
System.out.println("导出日期:"+date);
}
@Override
public void fileBody() {
System.out.println("文本文件体:");
System.out.println("表名:"+tablename);
}
@Override
public void fileTail() {
System.out.println("文本文件尾:");
System.out.println("输出人:"+username);
}
@Override
public void getResult() {
System.out.println("已导出完毕");
}
}
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Client {
public static void main(String[] args) throws ParseException {
Director director=new Director();
SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd");
Date date1 = dateformat.parse("2022-4-19");
Date date2 = dateformat.parse("2022-4-20");
FileBuilder fb1=new TextFileBuilder("001",date1,"student","李华");
FileBuilder fb2=new XmlFileBuilder("002",date2,"company","李四");
director.constract(fb1);
director.constract(fb2);
}
}