建造者模式

建造者模式

1.概述
1.1 问题:

​ 假设你要建造一座房子,最简单的是,先你需要建造四面墙和地板, 安装房门和一套窗户, 然后再建造一个屋顶。

​ 但是如果你想要一栋更宽敞更明亮的房屋,还想要暖气、排水和泳池等之类的又该怎么办?

public class Product {

    /**
     * 地基,必须建造
     */
    private String base;

    /**
     * 墙壁,必须建造
     */
    private String wall;

    /**
     * 屋顶,必须建造
     */
    private String roof;

    /**
     * 游泳池,可选建造
     */
    private String swimmingPool;

    /**
     * 暖气,可选建造
     */
    private String heating;

    /**
     * 花园,可选建造
     */
    private String garden;
}
1.2 解决方案

​ 这里现在有两个解决方法,一种是创建很多不同参数的构造方法(折叠构造函数模式),来满足不同的需求,但是这样灵活性较差;第二种是使用JavaBean,setter方法实例化对象。这里的属性设置是分开的,如果参数过多,很可能会出现遗漏和出错的情况。

1.2.1 使用不同参数的构造方法实现

代码展示

	
	public Product(String base, String wall, String roof) {
        this(base, wall, roof, "大游泳池");
    }

    public Product(String base, String wall, String roof, String swimmingPool) {
        this(base, wall, roof, swimmingPool, "地暖");
    }

    public Product(String base, String wall, String roof, String swimmingPool, String heating) {
        this(base, wall, roof, swimmingPool, heating, "花园");
    }

    public Product(String base, String wall, String roof, String swimmingPool, String heating, String garden) {
        this.base = base;
        this.wall = wall;
        this.roof = roof;
        this.swimmingPool = swimmingPool;
        this.heating = heating;
        this.garden = garden;
    }
1.2.2 使用JavaBean,setter实例化对象
  public String getBase() {
        return base;
    }

    public void setBase(String base) {
        this.base = base;
    }

    public String getWall() {
        return wall;
    }

    public void setWall(String wall) {
        this.wall = wall;
    }

    public String getRoof() {
        return roof;
    }

    public void setRoof(String roof) {
        this.roof = roof;
    }

    public String getSwimmingPool() {
        return swimmingPool;
    }

    public void setSwimmingPool(String swimmingPool) {
        this.swimmingPool = swimmingPool;
    }
//后面省略
2.实现
2.1 分析

场景分析

建造者模式建议将对象构造代码从产品类中抽取出来, 并将其放在一个名为生成器的独立对象中。

​ 将建造房子分成创建墙壁,创建房门,创建窗户等…,然后将创建房子分为固定的步骤, 组建房子的步骤是一样的。如果你想要不同的参数,只需要替换其中的某一个步骤就可以。

结构分析

  • Product: 最终要生成的对象,例如 House实例。

  • Builder: 构建者的抽象基类(有时会使用接口代替)。其定义了构建Product的抽象步骤,(构建房子的步骤)其实体类需要实现这些步骤。其会包含一个用来返回最终产品的方法Product getProduct()。

  • ConcreteBuilder(具体建造者): Builder的实现类。

  • Director(指导者): 决定如何构建最终产品的算法. 其会包含一个负责组装的方法void Construct(Builder builder), 在这个方法中通过调用builder的方法,就可以设置builder,等设置完成后,就可以通过builder的 getProduct()方法获得最终的产品。

类图分析
在这里插入图片描述

2.1 Product类
public class Product {

    /**
     * 地基,必须建造
     */
    private String base;

    /**
     * 墙壁,必须建造
     */
    private String wall;

    /**
     * 屋顶,必须建造
     */
    private String roof;

    /**
     * 游泳池,可选建造
     */
    private String swimmingPool;

    /**
     * 暖气,可选建造
     */
    private String heating;

    /**
     * 花园,可选建造
     */
    private String garden;

    public Product(String base, String wall, String roof) {
        this.base = base;
        this.wall = wall;
        this.roof = roof;
    }
    //省略setter和getter方法
}
2.2Builder接口
package com.renlon.Builder;

/**
 * 抽象构建者,定义了构建房子的抽象步骤
 *
 * @author: renlon 2023/03/02 23:53
 */
public interface Builder {

    /**
     * 建造游泳池
     */
    void buildSwimmingPool();

    /**
     * 建造地暖
     */
    void buildHeating();

    /**
     * 建造花园
     */
    void buildGarden();

    /**
     * 得到产品
     *
     * @return 返回产品
     */
    Product get();
}
2.3ConcreteBuilder实现类
  • 实现类A
package com.renlon.Builder;

/**
 * 实体房子A
 *
 * @author: renlon 2023/03/02 23:54
 */
public class ConcreteBuilderA implements Builder {

    private Product product;

    /**
     * 一个房子必须要构建地基,墙壁和屋顶
     *
     * @param base 用户指定的地基样式
     * @param wall 用户指定的墙壁样式
     * @param roof 用户指定的屋顶样式
     */
    public ConcreteBuilderA(String base, String wall, String roof) {
        product = new Product(base, wall, roof);
    }

    /**
     * 以下为可选实现功能,如果无需此设施,可选择不写方法体
     */
    @Override
    public void buildSwimmingPool() {
        product.setSwimmingPool("游泳池A");
    }

    @Override
    public void buildHeating() {
        //A房子没有地暖
    }

    @Override
    public void buildGarden() {
        product.setGarden("皇家后花园");
    }

    /**
     * 获得此产品
     *
     * @return 返回改产品
     */
    @Override
    public Product get() {
        return product;
    }
}

  • 实现类B
package com.renlon.Builder;

/**
 * 实体房子B
 *
 * @author: renlon 2023/03/02 23:56
 */
public class ConcreteBuilderB implements Builder {

    private Product product;

    /**
     * 一个房子必须要构建地基,墙壁和屋顶
     *
     * @param base 用户指定的地基样式
     * @param wall 用户指定的墙壁样式
     * @param roof 用户指定的屋顶样式
     */
    public ConcreteBuilderB(String base, String wall, String roof) {
        product = new Product(base, wall, roof);
    }

    /**
     * 以下为可选实现功能,如果无需此设施,可选择不写方法体
     */
    @Override
    public void buildSwimmingPool() {
        product.setSwimmingPool("游泳池B");
    }

    @Override
    public void buildHeating() {
        product.setHeating("地暖B");
    }

    @Override
    public void buildGarden() {
        //B房子没有花园
    }

    /**
     * 获得此产品
     *
     * @return 返回改产品
     */
    @Override
    public Product get() {
        return product;
    }
}

2.4 Director指挥类
package com.renlon.Builder;

/**
 * @author: renlon 2023/03/02 23:54
 */
public class Director {

    /**
     * 按照顺序执行构建房子的步骤
     *
     * @param builder 构建者,定义了构建房子的抽象步骤
     */
    public void construct(Builder builder) {
        builder.buildSwimmingPool();
        builder.buildHeating();
        builder.buildGarden();
    }
}
2.5检测
package com.renlon.Builder;

/**
 * @author: renlon 2023/03/03 19:49
 */
public class Demo {
    public static void main(String[] args) {
        //创建指导者对象
        Director director = new Director();

        //创建A房子,传入必须构造的地基,墙壁,屋顶参数
        ConcreteBuilderA builderA = new ConcreteBuilderA("地基A", "木头墙壁", "玻璃屋顶");

        //指导者调用方法,构建A的可选构造设施
        director.construct(builderA);

        //获得最终的A房子
        Product productA = builderA.get();
        System.out.println(productA.toString());

        ConcreteBuilderB builderB = new ConcreteBuilderB("地基B", "石头墙壁", "金属屋顶");
        director.construct(builderB);
        Product productB = builderB.get();
        System.out.println(productB.toString());
    }
}

运行结果

Product{base='地基A', wall='木头墙壁', roof='玻璃屋顶', swimmingPool='游泳池A', heating='null', garden='皇家后花园'}

Product{base='地基B', wall='石头墙壁', roof='金属屋顶', swimmingPool='游泳池B', heating='地暖B', garden='null'}
3. 总结
3.0 概念

​ 建造者模式是一种创建型设计模式,也叫生成器模式,用户只需要指定需要建造的类型就可以得到该类型对应的产品实例 , 不关心建造过程细节 。实际上就是构建包含多个组件的对象 , 采用相同的构建过程 , 创建不同的产品 。

3.1 优点
  1. 降低耦合性:建造者模式可以将对象的创建与使用分离,降低了对象之间的耦合性,使得系统更加灵活、易于维护和扩展。
  2. 增加可读性:使用建造者模式可以将复杂对象的创建过程分解为多个简单的步骤,使得代码更加清晰、易于理解和维护。
  3. 提高灵活性:通过建造者模式可以使用相同的创建过程来创建不同类型的对象,从而提高了系统的灵活性。
  4. 可以控制对象的创建过程:建造者模式可以控制对象的创建过程,从而可以根据需要对创建过程进行优化和调整,提高对象的性能和质量。
3.2 缺点
  1. 建造者模式的实现较为复杂,需要定义多个类和接口,因此增加了系统的复杂性。

  2. 如果对象较为简单,使用建造者模式可能会导致代码冗余,降低代码的可读性和可维护性。

  3. 对象创建过程一旦开始就无法中途取消或修改,因此建造者模式不适用于需要动态调整对象创建过程的场景。

3.3 工厂模式和建造者模式对比
  1. 建造者模式和工厂模式的不同点在于它们解决的问题和实现的方式。

  2. 建造者模式更适用于创建复杂的对象,而工厂模式更适用于创建简单的对象。建造者模式通常需要一个指导者来控制构建过程, 通过设置不同的可选参数,“定制化”创建不同属性的对象。

  3. 工厂模式只需要一个工厂类即可。此外,建造者模式通常会在最终创建对象之前进行多个步骤的处理,而工厂模式直接创建对象。

3.4 适用场景

结构复杂 :对象有非常复杂的内部结构,有很多的属性

分离创建和使用:想把复杂对象的创建和使用分离

当创建一个对象需要很多的步骤,适合使用建造者模式。当创建一个对象,只需要一个简单的方法就可以完成,适合使用工厂模式。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值