【设计模式 】| 建造者源码学习与实践

简介: 为什么要用建造者模式?在我们看来他和工厂模式的目的是一样的,就是为了获取对象。

前言

为什么要用建造者模式?在我们看来他和工厂模式的目的是一样的,就是为了获取对象。下面我们进一步来了解建造者模式是什么,以及他在我们业务开发中的使用场景。

纲要

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

什么是建造者模式?

建造者模式(Builder Pattern):将复杂对象的构造与其表示分离,以便同一构造过程可以创建不同的表示。

优缺点

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

四大主要角色

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

为什么要用建造者模式?

从两点来考虑

  1. 分阶段、分步骤的方法更适合多次运算结果类创建场景
  2. 不需要关心特定类型的建造者的具体算法实现

封装的变化

  1. 建造器的数量与具体实现
  2. 建造器内部创建多个属性
  3. 建造器的步骤

常用场景

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

实现Bean对象的构建

//建造者的抽象基类(接口)
public interface Builder<T> {
    T  build();
}
//最终构建的对象
public class User {
    private boolean isRef;
    private Object name;
    private String cardId;
    public Object getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "User{" +
            "name='" + name + '\'' +
            ", cardId='" + cardId + '\'' +
            '}';
    }
    private User(BuilderImpl builder){
        this.name = builder.name;
        this.cardId = builder.cardId;
    }
    private static BuilderImpl builder(){
        return new BuilderImpl();
    }
    // Builder 类的具体实现类 && 指挥者
    private static class BuilderImpl implements Builder<User> {
        private Object name;
        private String cardId;
        private boolean isRef;
        private BuilderImpl name(Object name){
            this.name = name;
            return this;
        }
        private BuilderImpl cardId(String cardId){
            this.cardId = cardId;
            return this;
        }
        private BuilderImpl isRef(boolean isRef){
            this.isRef = isRef;
            return this;
        }
        //指挥者,得到一个新的User对象
        @Override
        public User build(){
            if (!this.isRef){
                if (this.name == null || this.cardId == null){
                    throw new NullPointerException();
                }
            }else {
                if (!(this.name instanceof String)){
                    throw new IllegalArgumentException("name必须为String类型");
                }
            }
            return new User(this);
        }
    }
    public static void main(String[] args) {
        User u = User.builder().isRef(true).name(213).cardId("cardId").build();
        System.out.println(u);
    }
}

上面的实现逻辑,就是Lombok注释中,@Builder的大概实现,我们可以通过set方法设置建造者的变量值,自由组合来完成一个新的对象,

在结尾的build()方法中集中进行数据的校验。

源码学习案例

  1. JDK 类库中的 Appendable 接口
  2. StringBuilder

建造者的抽象基类(接口)

public interface Appendable {
        Appendable append(CharSequence csq) throws IOException;
        Appendable append(CharSequence csq, int start, int end) throws IOException;
        Appendable append(char c) throws IOException;
        }

Builder 类的具体实现类

abstract class AbstractStringBuilder implements Appendable, CharSequence {
    AbstractStringBuilder() {
    }
    AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }
    // Documentation in subclasses because of synchro difference
    @Override
    public AbstractStringBuilder append(CharSequence s) {
        if (s == null)
            return appendNull();
        if (s instanceof String)
            return this.append((String)s);
        if (s instanceof AbstractStringBuilder)
            return this.append((AbstractStringBuilder)s);
        return this.append(s, 0, s.length());
    }
    @Override
    public AbstractStringBuilder append(CharSequence s, int start, int end) {
        if (s == null)
            s = "null";
        if ((start < 0) || (start > end) || (end > s.length()))
            throw new IndexOutOfBoundsException(
                "start " + start + ", end " + end + ", s.length() "
                + s.length());
        int len = end - start;
        ensureCapacityInternal(count + len);
        for (int i = start, j = count; i < end; i++, j++)
            value[j] = s.charAt(i);
        count += len;
        return this;
    }
    @Override
    public AbstractStringBuilder append(char c) {
        ensureCapacityInternal(count + 1);
        value[count++] = c;
        return this;
    }
}

指挥者与具体的建造者

public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence
{
    public StringBuilder() {
        super(16);
    }
    public StringBuilder(int capacity) {
        super(capacity);
    }
    public StringBuilder(String str) {
        super(str.length() + 16);
        append(str);
    }
    @Override
    public StringBuilder append(Object obj) {
        return append(String.valueOf(obj));
    }
    @Override
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }
}

通过上面的代码可以看出他们之间的关系

  1. Appendable作为基类,提供三个方法
  2. AbstractStringBuilder实现了三个方法
  3. 在StringBuilder中继承了AbstractStringBuilder类,重写父类的方法,履行指导者的作用,调用append方法,返回一个StringBuilder对象

与工厂模式的区别

工厂模式:根据用户选择,来制作不同的食物,汉堡、面条、包子。

建造者模式:根据用户选择,来制作,加什么材料的汉堡。

  1. 工厂是生产某个配件,而建造者是整合配件
  2. 建造者注重步骤,按照步骤组装完整
  3. 工厂注重于创建不同对象

总结

建造者模式在我们业务开发中还是经常使用的, 他帮助我们自由组合创建对象,提高了灵活性,但是增加了代码量。

相关文章
|
15天前
|
设计模式 缓存 应用服务中间件
「全网最细 + 实战源码案例」设计模式——外观模式
外观模式(Facade Pattern)是一种结构型设计模式,旨在为复杂的子系统提供一个统一且简化的接口。通过封装多个子系统的复杂性,外观模式使外部调用更加简单、易用。例如,在智能家居系统中,外观类可以同时控制空调、灯光和电视的开关,而用户只需发出一个指令即可。
125 69
|
1天前
|
设计模式 存储 关系型数据库
「全网最细 + 实战源码案例」设计模式——六大设计原则
本文介绍了面向对象设计中的六大原则,旨在提高软件系统的可维护性、可复用性和可拓展性。这些原则包括:开闭原则(OCP)、里氏代换原则(LSP)、依赖倒转原则(DIP)、接口隔离原则(ISP)、迪米特法则(LoD)和合成复用原则(CARP)。每项原则通过具体示例展示了如何通过抽象、多态、组合等方式降低耦合度,增强系统的灵活性与稳定性,从而提升开发效率并降低成本。
19 10
|
1天前
|
设计模式 缓存 安全
「全网最细 + 实战源码案例」设计模式——单例设计模式
单例模式是一种创建型设计模式,确保一个类在整个程序运行期间只有一个实例,并提供一个全局访问点来获取该实例。它常用于控制共享资源的访问,如数据库连接、配置管理等。实现方式包括饿汉式(类加载时初始化)、懒汉式(延迟加载)、双重检查锁、静态内部类和枚举单例等。其中,枚举单例最简单且安全,能有效防止反射和序列化破坏。
19 7
|
29天前
|
存储 设计模式 算法
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
行为型模式用于描述程序在运行时复杂的流程控制,即描述多个类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,它涉及算法与对象间职责的分配。行为型模式分为类行为模式和对象行为模式,前者采用继承机制来在类间分派行为,后者采用组合或聚合在对象间分配行为。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象行为模式比类行为模式具有更大的灵活性。 行为型模式分为: • 模板方法模式 • 策略模式 • 命令模式 • 职责链模式 • 状态模式 • 观察者模式 • 中介者模式 • 迭代器模式 • 访问者模式 • 备忘录模式 • 解释器模式
【23种设计模式·全精解析 | 行为型模式篇】11种行为型模式的结构概述、案例实现、优缺点、扩展对比、使用场景、源码解析
|
29天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。 结构型模式分为以下 7 种: • 代理模式 • 适配器模式 • 装饰者模式 • 桥接模式 • 外观模式 • 组合模式 • 享元模式
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
29天前
|
设计模式 存储 安全
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
创建型模式的主要关注点是“怎样创建对象?”,它的主要特点是"将对象的创建与使用分离”。这样可以降低系统的耦合度,使用者不需要关注对象的创建细节。创建型模式分为5种:单例模式、工厂方法模式抽象工厂式、原型模式、建造者模式。
【23种设计模式·全精解析 | 创建型模式篇】5种创建型模式的结构概述、实现、优缺点、扩展、使用场景、源码解析
|
2月前
|
设计模式 算法 开发者
探索编程语言中的设计模式:从理论到实践
设计模式,这一编程世界中的灯塔,为无数开发者照亮了复杂问题解决的道路。本文将深入探讨设计模式在编程实践中的运用,以代码示例揭示其背后的智慧。无论你是初学者还是资深开发者,都能在这里找到启发和共鸣。让我们一起领略设计模式的魅力,开启编程世界的新篇章!
|
2月前
|
设计模式 监控 算法
Python编程中的设计模式应用与实践感悟###
在Python这片广阔的编程疆域中,设计模式如同导航的灯塔,指引着开发者穿越复杂性的迷雾,构建出既高效又易于维护的代码结构。本文基于个人实践经验,深入探讨了几种核心设计模式在Python项目中的应用策略与实现细节,旨在为读者揭示这些模式背后的思想如何转化为提升软件质量的实际力量。通过具体案例分析,展现了设计模式在解决实际问题中的独特魅力,鼓励开发者在日常编码中积极采纳并灵活运用这些宝贵的经验总结。 ###
|
2月前
|
设计模式 开发者 Python
Python编程中的设计模式应用与实践感悟####
本文作为一篇技术性文章,旨在深入探讨Python编程中设计模式的应用价值与实践心得。在快速迭代的软件开发领域,设计模式如同导航灯塔,指引开发者构建高效、可维护的软件架构。本文将通过具体案例,展现设计模式如何在实际项目中解决复杂问题,提升代码质量,并分享个人在实践过程中的体会与感悟。 ####
|
3月前
|
设计模式 API 持续交付
深入理解微服务架构:设计模式与实践
【10月更文挑战第19天】介绍了微服务架构的核心概念、设计模式及最佳实践。文章详细探讨了微服务的独立性、轻量级通信和业务能力,并介绍了聚合器、链式和发布/订阅等设计模式。同时,文章还分享了实施微服务的最佳实践,如定义清晰的服务边界、使用API网关和服务发现机制,以及面临的挑战和职业心得。

热门文章

最新文章

  • 1
    设计模式转型:从传统同步到Python协程异步编程的实践与思考
    64
  • 2
    C++一分钟之-设计模式:工厂模式与抽象工厂
    55
  • 3
    《手把手教你》系列基础篇(九十四)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-下篇(详解教程)
    65
  • 4
    C++一分钟之-C++中的设计模式:单例模式
    80
  • 5
    《手把手教你》系列基础篇(九十三)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-上篇(详解教程)
    52
  • 6
    《手把手教你》系列基础篇(九十二)-java+ selenium自动化测试-框架设计基础-POM设计模式简介(详解教程)
    82
  • 7
    Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
    70
  • 8
    Java面试题:设计模式在并发编程中的创新应用,Java内存管理与多线程工具类的综合应用,Java并发工具包与并发框架的创新应用
    54
  • 9
    Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
    63
  • 10
    Java面试题:请列举三种常用的设计模式,并分别给出在Java中的应用场景?请分析Java内存管理中的主要问题,并提出相应的优化策略?请简述Java多线程编程中的常见问题,并给出解决方案
    137