把书读薄 | 《设计模式之美》设计模式与范式(创建型-建造者模式)

简介: 本文是 设计模式与范式:创建型(46),建造者模式(Builder Design Pattern) 也有人叫做生成器模式,又是一个很常用的创建型设计模式,非常轻松的一节~二手知识加工难免有所纰漏,感兴趣有时间的可自行查阅原文,谢谢。

0x1、为什么需要Builder模式


当类中的属性很多时,为了避免构造函数参数列表过长影响代码可读性与易用性,可以通过 构造函数配合set()方法 解决。


但如果存在下述情况中的一种,就要考虑使用Builder模式了:


  • ① 强制创建对象的时候就设置一些必填属性(放构造方法中),如果必填属性很多,又会出现构造函数参数列表过长的问题。如果把必填属性放到set()中设置,那么校验必填属性是否已填写的逻辑就无处安放了;


  • ② 类的属性间有一定的依赖关系或约束条件,如果用构造函数+set()方法的设计思路,依赖关系和约束条件的校验逻辑就无处安放了;


  • ③ 希望创建不可变对象(创建后就不能修改内部属性),就不能在类中暴露set()方法;


0x2、Builder模式与Factory模式的区别


  • 建造者模式 → 用于创建 一种类型 的复杂对象,通过设置不同的可选参数,定制化地创建不同的对象;


  • 工厂模式 → 用于创建 不同但是类型相关 的对象,由给定的参数来决定创建哪种类型的对象;


一个解释两者区别的经典例子


顾客进一家餐馆点餐,利用工厂模式,根据用户的不同选择,来制作不同的事物,如披萨、汉堡、沙拉。对于披萨来说,用户有各种配料可以定制,如芝士、西红柿、起司等,我们通过建造者模式根据用户选择的不同配料来制作披萨。


Builder模式一般由下述四个角色组成:


网络异常,图片无法展示
|


还是那句话,不要生搬硬套设计模式,四个角色不一定都要有,最常见的是Product中包裹一个Builder,直接生成,比如Android中的AlertDialog。


0x3、简单的代码示例


自定义游戏角色时,游戏角色由:性别,脸部,衣服三个部分组成,用户可以根据自己的喜好配置生成不同的角色。先写下没有引入Builder模式之前:


public class Role {
    private static final int DEFAULT_SEX = 0;
    private static final String DEFAULT_FACE = "大众";
    private static final String DEFAULT_CLOTHE = "便装";
    private String name;    // 角色名,必填,故强制放到构造函数中设置
    private int sex = DEFAULT_SEX;  // 性别:0-男、1-女
    private String face = DEFAULT_FACE;
    private String clothe = DEFAULT_CLOTHE;
    public Role(String name) { this.name = name; }
    public int getSex() { return sex; }
    public void setSex(int sex) { this.sex = sex; }
    public String getFace() { return face; }
    public void setFace(String face) { this.face = face; }
    public String getClothe() { return clothe; }
    public void setClothe(String clothe) { this.clothe = clothe; }
    public String show() {
        return "您创建了角色【" + name + "】 → " + (sex == 0 ? "男性角色 " : "女性角色 ") + face + "脸 身穿" + clothe;
    }
}
// 测试用例
public class Game {
    public static void main(String[] args) {
        Role role = new Role("王司徒");
        role.setFace("慈眉善目");
        role.setClothe("古装");
        System.out.println(role.show());
    }
}


运行结果如下:


网络异常,图片无法展示
|


接着用Builder模式改造一波:


// 产品类
public class Role {
    private String name;    // 角色名
    private int sex;  // 性别:0-男、1-女
    private String face;
    private String clothe;
    public Role(Builder builder) {
        this.name = builder.getName();
        this.sex = builder.getSex();
        this.face = builder.getFace();
        this.clothe = builder.getClothe();
    }
    public String show() {
        return "您创建了角色【" + name + "】 → " + (sex == 0 ? "男性角色 " : "女性角色 ") + face + "脸 身穿" + clothe;
    }
}
// 建造者类
public class Builder {
    private static final int DEFAULT_SEX = 0;
    private static final String DEFAULT_FACE = "大众";
    private static final String DEFAULT_CLOTHE = "便装";
    private String name;    // 角色名,必填
    private int sex = DEFAULT_SEX;  // 性别:0-男、1-女
    private String face = DEFAULT_FACE;
    private String clothe = DEFAULT_CLOTHE;
    public Role build() {
        // 将校验逻辑放到这里,必填项、约束条件等,只有都通过了才构建对象
        if(name == null || name.isEmpty()) { return null; }
        return new Role(this);
    }
    public String getName() { return name; }
    public int getSex() { return sex; }
    public String getFace() { return face; }
    public String getClothe() { return clothe; }
    // 也可以在set方法中进行逻辑校验
    public Builder setName(String name) { this.name = name; return this; }
    public Builder setSex(int sex) { this.sex = sex; return this; }
    public Builder setFace(String face) { this.face = face; return this; }
    public Builder setClothe(String clothe) { this.clothe = clothe; return this; }
}
// 测试用例
public class Game {
    public static void main(String[] args) {
        Role role = new Builder()
                .setName("杰哥")
                .setFace("超勇")
                .build();
        System.out.println(role.show());
    }
}


另外,使用创建者模式还可以避免对象存在 无效状态,比如长方形,你通过set()设置了长度,没设置宽度,此时的长方形对象是没有意义的,或者说处于无效状态。而在创建者模式中,先设置好创建者的变量,然后再一次性地创建产品对象,就可以规避这个问题,使得对象一直处于 有效状态。从示例代码也可以看出Builder的优缺点:


优点


  • 满足开闭原则 (建造者们都相对独立,替换/新增方便)
  • 分离创建和使用 (调用方无需了解内部细节,通过统一方法接口调用即可组合成不同的对象实例)
  • 可以自由的组合对象的创建过程 (将复杂的创建步骤拆解为单个独立的创建步骤,可自由拼接)


缺点


  • 代码量增加 (属性写两份,类Double)
  • 使用范围有限 (对象存在较多共同点,如果对象实例间差异太大,就不适合使用Builder模式了)
  • 容易引起超大类


相关文章
|
8天前
|
设计模式 Java
【设计模式系列笔记】建造者模式
建造者模式是一种创建型设计模式,用于将复杂对象的构建与其表示分离,使构建过程可定制。关键元素包括产品类(定义要构建的对象)、建造者接口(定义构建方法)、具体建造者类(实现构建过程)和指导者类(负责构建过程)。通过建造者模式,客户端可以灵活地创建具有不同表示的复杂对象,提高代码的可读性和可维护性,尤其适用于构建过程复杂且包含多个可选部分的情况。
109 1
|
8天前
|
设计模式 安全 Java
构建未来应用:Java设计模式 - 建造者模式(Builder)在现代编程中的应用
【4月更文挑战第7天】建造者模式是提升代码质量的关键,尤其在复杂环境中。它分步骤构建对象,将构建与表示分离,适用于UI构建、数据模型组装、配置文件解析和网络请求构造等场景。最佳实践包括明确构建步骤、提供默认值、支持链式调用和确保线程安全。然而,过多步骤、不一致状态和性能问题是使用时需注意的问题。掌握建造者模式对于现代编程至关重要。
|
7天前
|
设计模式 搜索推荐 数据库连接
第二篇 创建型设计模式 - 灵活、解耦的创建机制
第二篇 创建型设计模式 - 灵活、解耦的创建机制
|
8天前
|
设计模式 uml
【设计模式】建造者模式就是游戏模式吗?
【设计模式】建造者模式就是游戏模式吗?
12 0
|
8天前
|
设计模式 uml
大话设计模式(3)——造物者一般的建造者模式
大话设计模式(3)——造物者一般的建造者模式
9 1
大话设计模式(3)——造物者一般的建造者模式
|
8天前
|
设计模式 JavaScript 前端开发
[设计模式Java实现附plantuml源码~创建型] 复杂对象的组装与创建——建造者模式
[设计模式Java实现附plantuml源码~创建型] 复杂对象的组装与创建——建造者模式
|
8天前
|
设计模式 Java Go
[设计模式Java实现附plantuml源码~创建型] 对象的克隆~原型模式
[设计模式Java实现附plantuml源码~创建型] 对象的克隆~原型模式
|
8天前
|
设计模式 Java Go
[设计模式Java实现附plantuml源码~创建型] 产品族的创建——抽象工厂模式
[设计模式Java实现附plantuml源码~创建型] 产品族的创建——抽象工厂模式
|
8天前
|
设计模式 存储 JavaScript
[设计模式Java实现附plantuml源码~创建型] 多态工厂的实现——工厂方法模式
[设计模式Java实现附plantuml源码~创建型] 多态工厂的实现——工厂方法模式
|
8天前
|
设计模式 Java Go
[设计模式Java实现附plantuml源码~创建型] 集中式工厂的实现~简单工厂模式
[设计模式Java实现附plantuml源码~创建型] 集中式工厂的实现~简单工厂模式