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

简介: 本文是 设计模式与范式:创建型(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模式了)
  • 容易引起超大类


相关文章
|
3月前
|
设计模式 算法
设计模式--建造者模式 builder
这篇文章通过一个电脑购买的例子,详细解释了建造者模式的四个角色(产品类、抽象构建者、实体构建类和指导者类),并提供了相应的代码实现,阐述了建造者模式在设计复杂对象时的应用和优势。
设计模式--建造者模式 builder
|
6月前
|
设计模式
**工厂模式与抽象工厂模式**都是创建型设计模式,用于封装对象创建,减少耦合
【6月更文挑战第23天】**工厂模式与抽象工厂模式**都是创建型设计模式,用于封装对象创建,减少耦合。工厂模式专注于单个对象,通过具体工厂创建具体产品,适用于简单对象创建;抽象工厂则关注一系列相关产品,提供创建一族对象的接口,适用于处理多个不兼容产品族。选择模式基于问题域的复杂性,单个产品需求时用工厂模式,多产品族时用抽象工厂模式。
33 5
|
18天前
|
设计模式 JavaScript Java
Java设计模式:建造者模式详解
建造者模式是一种创建型设计模式,通过将复杂对象的构建过程与表示分离,使得相同的构建过程可以创建不同的表示。本文详细介绍了建造者模式的原理、背景、应用场景及实际Demo,帮助读者更好地理解和应用这一模式。
|
3月前
|
设计模式 算法 Java
Java设计模式-建造者模式(6)
Java设计模式-建造者模式(6)
|
7月前
|
设计模式 搜索推荐 数据库连接
第二篇 创建型设计模式 - 灵活、解耦的创建机制
第二篇 创建型设计模式 - 灵活、解耦的创建机制
|
4月前
|
设计模式 XML 存储
【四】设计模式~~~创建型模式~~~建造者模式(Java)
文章详细介绍了建造者模式(Builder Pattern),这是一种创建型设计模式,用于将复杂对象的构建与其表示分离,允许分步骤创建一个复杂的对象而无需指定其内部的具体构造细节。通过定义抽象建造者、具体建造者、指挥者和产品角色,建造者模式允许通过相同的构建过程创建不同的产品表示,提高了系统的灵活性和扩展性。
|
6月前
|
设计模式 Oracle Java
工厂模式是一种创建型设计模式,它提供了一种创建对象的最佳方式。
【6月更文挑战第20天】工厂模式简化对象创建,根据参数或条件生成MySQL或Oracle数据库连接。`DatabaseConnectionFactory`作为工厂,动态返回具体连接类型。装饰器模式则用于运行时动态增加对象功能,如`LoggingDecorator`为`Runnable`对象添加日志记录,保持代码整洁。在`Main`类中展示了如何使用这两种模式。
42 6
|
6月前
|
设计模式 算法
建造者模式-大话设计模式
建造者模式-大话设计模式
|
7月前
|
设计模式 uml
大话设计模式(3)——造物者一般的建造者模式
大话设计模式(3)——造物者一般的建造者模式
43 1
大话设计模式(3)——造物者一般的建造者模式
|
5月前
|
设计模式 JavaScript
js设计模式【详解】—— 建造者模式
js设计模式【详解】—— 建造者模式
57 0