建造者模式

一、主要解决的问题场景

(1)通过将多个简单对象通过⼀步步的组装构建出⼀个复杂对象的过程,适用前提是物料不变,组合多变的情况。即需要生成的产品对象有复杂的内部结构,且这些产品对象具有共性。

(2)隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品(组合多变)

(3)适用于一个具有较多属性的复杂对象的创建过程
(4)创建对象的时候,需要将过多必填字段放入构造方法,而导致构造方法参数列表过长
(5)需要对传入对象的各项参数进行校验,甚至各参数之间还有相互约束关系,那么使用构造方法或者set方法就很难处理这种依赖关系或者约束条件的校验逻辑

二、主要实现方式

建造者模式调用关系
在这里插入图片描述

首先我们需要创建一个抽象的Builder类,比如CarBuilder,里面包含的是汽车各个零部件的生产构建过程。

public abstract class CarBuilder {

    /**
     * 构建引擎
     */
    public abstract CarBuilder buildEngine(String engine);

    /**
     * 构建外壳
     */
    public abstract CarBuilder buildShell(String shell);

    /**
     * 构建电子系统
     */
    public abstract CarBuilder buildElecSystem(String elecSystem);

    /**
     * 构建控制系统
     */
    public abstract CarBuilder buildControlSystem(String controlSystem) throws Exception;

    /**
     * 构建车轮
     */
    public abstract CarBuilder buildWheel(String wheel);

    /**
     * 构建轴承
     */
    public abstract CarBuilder buildBearing(String bearing);

    /**
     * 返回产品:有的地方是将方法名叫“build”,道理一样
     */
    public abstract CarProduct getProduct();
}

最终构建出的是一个汽车产品 CarProduct,我们给定默认值,这样,如果我们的Commander没有给定参数,就取用默认参数

@Setter
@Getter
public class CarProduct {

    /**
     * 发动机:默认 V8
     */
    private String engine = "V8";

    /**
     * 外壳:默认 碳纤维
     */
    private String shell = "碳纤维";

    /**
     * 电子系统:默认 AI
     */
    private String elecSystem = "AI";

    /**
     * 控制系统:默认 AutoDrive
     */
    private String controlSystem = "AutoDrive";

    /**
     * 车轮:默认 米其林
     */
    private String wheel = "米其林";

    /**
     * 轴承:默认 冷轧钢板
     */
    private String bearing = "冷轧钢板";
	
    /**
     * 重写toString,便于打印结果
     */
    @Override
    public String toString() {
        return "CarProduct{" +
                "engine='" + engine + '\'' +
                ", shell='" + shell + '\'' +
                ", elecSystem='" + elecSystem + '\'' +
                ", controlSystem='" + controlSystem + '\'' +
                ", wheel='" + wheel + '\'' +
                ", bearing='" + bearing + '\'' +
                '}';
    }
}

我们可以创建多个不同品牌商的Builder实现类,重写父类方法,同时内部创建产品类,并返回对应的具体产品

public class BugattiBuilder extends CarBuilder{

    /**
     * 具体建造者实现具体的产品对象
     */
    private CarProduct carProduct;

    /**
     * 无参构造:必须由建造者自己去实例化产品对象
     */
    private BugattiBuilder() {
        this.carProduct = new CarProduct();
    }

    /**
     * 对外只提供一个静态方法调用创建builder
     */
    public static CarBuilder carBuild() {
        return new BugattiBuilder();
    }
	
    /**
     * 以下是对父类方法的,关于汽车构建过程的重写
     * 注意:return this,返回这个builder类本身,这样可以链式编成
     */
    @Override
    public CarBuilder buildEngine(String engine) {
        carProduct.setEngine(engine);
        return this;
    }

	@Override
    public CarBuilder buildControlSystem(String controlSystem) throws Exception {
        //可以单独验参
        if (StringUtils.isEmpty(controlSystem)) {
            throw new Exception("没有控制系统!");
        }
        carProduct.setControlSystem(controlSystem);
        return this;
    }
	
    .......
	
    /**
     * 返回具体的产品对象
     */    
    @Override
    public CarProduct getProduct() {
        //最后组合返回结果的时候可以将相互依赖或约束的关系进行校验
        //比如:如果没有控制系统,那就不建造电子系统
        //或者是一些大小的比较,比如ES的builder对象的lt和gt属性操作
        if (StringUtils.isEmpty(this.carProduct.getControlSystem())) {
            this.carProduct.setElecSystem(null);
        }
        return carProduct;
    }
}

调用关系图中的Commander,其实是车间主任,或者调用方自己,这样可以很灵活的指导并创建多种不同组合的产品,以满足调用方需求

@RunWith(JUnit4.class)
public class CarBuilderTest {

    @Test
    public void testCarBuild() {
        CarProduct product = BugattiBuilder.carBuild() //创建建造者对象
                .buildEngine("V19") //自定义引擎
                .buildControlSystem("No-AutoDrive") //自定义控制系统
                .buildWheel("国产") //自定义车轮
                .getProduct();
        System.out.println(product.toString()); //{engine='V19', shell='碳纤维', elecSystem='AI', controlSystem='No-AutoDrive', wheel='国产', bearing='冷轧钢板'}
    }
}

三、优缺点

3.1 优点

(1)产品的建造和表示分离(建造的具体过程和最终展示的组合结果),实现了解耦。使用建造者模式可以使客户端不必知道产品内部的组成细节

(2)将复杂的创建步骤分解在不同方法中,使得创建过程更加清晰

(3)具体的建造者类之间是相互独立的,有利于系统扩展,符合开闭原则

3.2 缺点

(1)使用范围受限:必须保证建造的产品有很多的共同点,组成部分类似,如果差异性很大,很多,不要使用

(2)如果产品内部变化复杂,需要定义很多的具体实现的建造者类,导致系统庞大

3.3 与工厂模式的最大区别

着眼点不同,工厂模式着眼于全局,各个品牌簇和各种类型的产品,调用工厂方法返回对应品牌,对应类型产品的结果;而建造者模式着眼于局部,不调用相关方法,而是指导生产,如何生产出满足需求的具体而复杂的产品,返回一个完整对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值