一个菜鸡JAVA后端的博客~

设计模式-建造者模式

定义

  • Separate the construction of a complex object from its representation so that the saame construction process can create different representations.(将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。)
  • 建筑者模式通常有四个角色
    • Product产品类:通常是实现了模板方法模式,也就是有模板方法和基本方法
    • Builder抽象建造者:规范产品的组建,一般是由子类实现
    • ConcreteBuilder具体建造者:实现抽象类定义的所有方法,并返回一个组建好的对象。
    • Director导演类:负责安排已有模块的顺序,然后告诉Builder开始建造。

优点

  • 封装性:使用建造者模式可以使客户端不必知道产品内部的组成细节
  • 建造者独立,容易扩展。
  • 方便用户自由的创建复杂的对象
  • 便于控制细节风险:由于具体的建造者是独立的,因此可以对建造过程逐步细化,并不对其他模块产生任何影响。

使用场景

  • 场景:
    • 相同的方法,不同的执行顺序,产生不同的事件结果时,可以使用建造者模式
    • 多个零件或部件,都可以装配到一个对象中,但是产生的运行结果又不相同时,可以使用建造者模式
    • 产品类非常复杂,或者产品类中的调用顺序不同产生了不同的效能
    • 在对象创建过程中会使用到系统中的一些其他对象,这些对象在产品对象的创建过程中不易得到时。(注意:这种方法只适用于维护阶段,因为一个对象不容易获得,这应该是在设计阶段考虑的问题,通过建造者模式来柔化创建过程,本来就违反了设计的最初目标)

代码

通用类图

建造者模式通用类图

基本的建造者模式

类图

建造者模式基本类图

代码

产品类代码

package com.pattern.builder.products;

import java.util.List;

/**
 * 建造者模式的产品
 */
public class Product {
    // 产品名称
    private String productName;
    // 产品的组成部分
    private List<String> productParts;

    // 添加产品的组成部分
    public void addProductPart(String part) {
        this.productParts.add(part);
    }

    public Product(){}
    public Product(String productName,List<String> productParts){
        this.productName = productName;
        this.productParts = productParts;
    }

    public String getProductName() {
        return productName;
    }

    public void setProductName(String productName) {
        this.productName = productName;
    }

    public List<String> getProductParts() {
        return productParts;
    }

    public void setProductParts(List<String> productParts) {
        this.productParts = productParts;
    }

    @Override
    public String toString() {
        return "Product [productName=" + productName + ", productParts=" + productParts + "]";
    }
    
}

建造者(抽象类

package com.pattern.builder.template;

import com.pattern.builder.products.Product;

public abstract class TemplateBuilder {
    // 产品
    protected Product product = new Product();
    public abstract void addPart(String part);
    public abstract void setName(String name);
    // 生产产品
    public Product create(){
        return this.product;
    }
    // 清理场景,用于清理上次的场景,防止数据出错
    public void clear(){
        product = new Product();
    }
}

具体的建造者(继承自建造者

package com.pattern.builder.template;

import java.util.ArrayList;

/**
 * 具体的建造者实现类
 */
public class TemplateConcreteBuilder extends TemplateBuilder{

    @Override
    public void addPart(String part) {
        // 如果产品ProductParts没有初始化则初始化
        if(super.product.getProductParts() == null){
            super.product.setProductParts(new ArrayList<String>());
        }
        super.product.addProductPart(part);
    }

    @Override
    public void setName(String name) {
        super.product.setProductName(name);
    }
    
}

导演类(用于指导建造者创建,可有可无)

package com.pattern.builder.template;

/**
 * 导演类,用于指导建造,即通过模板建造预定好的产品
 */

import com.pattern.builder.products.Product;

public class TemplateDirector {
    private TemplateBuilder builder;

    public TemplateDirector(TemplateBuilder builder) {
        this.builder = builder;
    }

    // 预定好的产品模板1
    public Product getProduct1() {
        // 显示调用一次清理方法清理上一次可能残留下来的产品
        builder.clear();
        builder.setName("汽车");
        builder.addPart("发动机");
        builder.addPart("轮胎");
        builder.addPart("引擎");
        return builder.create();
    }

    // 预定好的产品模板2
    public Product getProduct2() {
        // 显示调用一次清理方法清理上一次可能残留下来的产品
        builder.clear();
        builder.setName("自行车");
        builder.addPart("车龙头");
        builder.addPart("轮胎");
        builder.addPart("车链");
        return builder.create();
    }
}

测试代码

package com.pattern;

import com.pattern.builder.extend.SimpleBuilder;
import com.pattern.builder.products.Product;
import com.pattern.builder.template.TemplateBuilder;
import com.pattern.builder.template.TemplateConcreteBuilder;
import com.pattern.builder.template.TemplateDirector;

import org.junit.Test;

public class BuilderTest {
    // 通用建造者模式测试
    @Test
    public void TemplateBuilderTest() {
        System.out.println("-----------创建一个建造者对象-------------");
        TemplateBuilder builder = new TemplateConcreteBuilder();
        System.out.println("-----------创建一个导演对象-------------");
        TemplateDirector director = new TemplateDirector(builder);
        System.out.println("-----------创建一个预定的产品:汽车-------------");
        Product car = director.getProduct1();
        System.out.println(car.toString());
        System.out.println("-----------创建一个预定产品:自行车-------------");
        Product bike = director.getProduct2();
        System.out.println(bike.toString());
    }
}

结果

基本建造者模式执行结果

简化的建造者模式

简化后的建造者模式在开源框架中的使用较多,如httpclient的MultipartEntityBuilder

类图

简化的建造者模式类图

代码

产品类(同上
简化后的建造者

package com.pattern.builder.extend;

import java.util.ArrayList;
import java.util.List;

import com.pattern.builder.products.Product;

/**
 * 建造者模式的一个简化版,使得构建的过程比较明了清晰。
 */
public class SimpleBuilder {
    private String productName;
    private List<String> productParts;
    // 返回一个建筑者对象
    public static SimpleBuilder create(){
        return new SimpleBuilder();
    }
    // 添加产品名字
    public SimpleBuilder setProductName(String productName){
        this.productName = productName;
        return this;
    }
    // 添加产品组成部分
    public SimpleBuilder addProductPart(String part){
        if(this.productParts == null){
            this.productParts = new ArrayList<String>();
        }
        this.productParts.add(part);
        return this;
    }
    // 清理场景
    public void clear(){
        this.productName = null;
        this.productParts.clear();;
    }
    // 创建产品
    public Product build(){
        Product product = new Product(this.productName, this.productParts);
        return product;
    }
}

测试代码

package com.pattern;

import com.pattern.builder.extend.SimpleBuilder;
import com.pattern.builder.products.Product;
import com.pattern.builder.template.TemplateBuilder;
import com.pattern.builder.template.TemplateConcreteBuilder;
import com.pattern.builder.template.TemplateDirector;

import org.junit.Test;

public class BuilderTest {
    // 简化的建造者模式测试
    @Test
    public void SimpleBuilderTest() {
        System.out.println("-----------通过静态方法创建一个建造者对象-------------");
        SimpleBuilder builder = SimpleBuilder.create();
        System.out.println("-----------创建一个预定的产品:汽车-------------");
        Product car = builder.setProductName("汽车").addProductPart("发动机").addProductPart("轮胎").addProductPart("引擎")
                .build();
        System.out.println(car.toString());
        System.out.println("-----------要用同一个建筑者对象创建一个新的产品需要先清理前一个场景-------------");
        builder.clear();
        System.out.println("-----------创建一个预定产品:自行车-------------");
        Product bike = builder.setProductName("自行车").addProductPart("车龙头").addProductPart("轮胎").addProductPart("车链")
                .build();
        System.out.println(bike.toString());
    }
}

运行结果

简化的建造者模式执行结果

注意

  • 如果一个建造者要建造多个不同的对象,请注意调用clear来清理场景。顺带一提:如果ArrayList和HashMap定义为类的成员变量,那在方法中的调用一定要做一个clear动作防止数据混乱。
  • 建造者模式关注的是零件类型和装配顺序,这是它与工厂方法模式最大的不同。虽然同为创建类模式,但是注重点不同。

NOTE: 文章若无特别说明均为原创文章,如果要转载请保留出处!