建造者模式 Builder Pattern

在创建一个对象的时候,构造器参数有点多,而且有些参数还是可选的,再者还有不少同类型的,那就更应该使用 builder 模式了。

使用 Builder 模式的初衷是 把易变性(mutability)移动到Builder类,而使得要被创建的对象变得不可变(immutable)。

传统方式

创建静态内部类 Builder ,此 Builder 和外部类拥有一样的属性。包括一些返回 this对象的 setter方法,和一个 build 方法调用 外部类的 以builder对象为参数构造器 来创建 外部类对象。

@Getter
public class Blog {
    private final String title;
    private final String content;
    private final String label;
    private final String author;

    public Blog(BlogBuilder builder){
        this.title = builder.title;
        this.content = builder.content;
        this.label = builder.label;
        this.author = builder.author;
    }

    static class BlogBuilder{
        private String title;
        private String content;
        private String label;
        private String author;

        BlogBuilder title(String title){
            this.title = title;
            return this;
        }
        BlogBuilder content(String content){
            this.content = content;
            return this;
        }
        BlogBuilder label(String label){
            this.label = label;
            return this;
        }
        BlogBuilder author(String author){
            this.author = author;
            return this;
        }
        Blog build(){
            return new Blog(this);
        }
    }
}

对象创建过程如下:

    @Test
    public void test(){
        Blog blog = new Blog.BlogBuilder()
                .author("dachuili")
                .content("classic/generic/lombok builder pattern")
                .label("design patterns")
                .title("builder pattern")
                .build();
        assertSame(blog.getAuthor(), "dachuili");
        assertSame(blog.getTitle(), "builder pattern");
        assertSame(blog.getContent(), "classic/generic/lombok builder pattern");
        assertSame(blog.getLabel(), "design patterns");
    }

Lombok方式

Lombok提供了注解  @Builder  ,一步实现  Builder 模式。不要忘了和@Value 一起用。

import lombok.Builder;
import lombok.Data;
import lombok.Value;

@Builder
@Value
@Data
public class Article {
    private String title;
    private String content;
    private String label;
    private String author;
}

创建过程:

    @Test
    public void test(){
        Article article = Article.builder()
                .author("dachuili")
                .content("classic/generic/lombok builder pattern")
                .label("design patterns")
                .title("builder pattern")
                .build();
        assertSame(article.getAuthor(), "dachuili");
        assertSame(article.getTitle(), "builder pattern");
        assertSame(article.getContent(), "classic/generic/lombok builder pattern");
        assertSame(article.getLabel(), "design patterns");
    }

是不是很 easy!很 convenient!

@Builder 帮我们创建了 Builder 对象以及 这些返回 this对象的 setter方法。以下是lombok生成的ArticleBuilder对象 代码。

和传统方式并为区别。

    @Generated
    public static ArticleBuilder builder() {
        return new ArticleBuilder();
    }

    @Generated
    public static class ArticleBuilder {
        @Generated
        private String title;
        @Generated
        private String content;
        @Generated
        private String label;
        @Generated
        private String author;

        @Generated
        ArticleBuilder() {
        }

        @Generated
        public ArticleBuilder title(String title) {
            this.title = title;
            return this;
        }

        @Generated
        public ArticleBuilder content(String content) {
            this.content = content;
            return this;
        }

        @Generated
        public ArticleBuilder label(String label) {
            this.label = label;
            return this;
        }

        @Generated
        public ArticleBuilder author(String author) {
            this.author = author;
            return this;
        }

        @Generated
        public Article build() {
            return new Article(this.title, this.content, this.label, this.author);
        }
    }

通用的Builder

借助于 Java 8 提供的 Supplier和 BiConsumer 创建一个通用工具类,好玩是好玩,强行捏了一个builder出来,感觉违背了 builder模式的初衷,回到了 JavaBeans Pattern 那种setter方法。

public class GenericBuilder<T> {
    private final Supplier<T> supplier;

    private GenericBuilder(Supplier<T> supplier) {
        this.supplier = supplier;
    }

    public static <T> GenericBuilder<T> of(Supplier<T> supplier) {
        return new GenericBuilder<>(supplier);
    }

    public <P> GenericBuilder<T> with(BiConsumer<T, P> consumer, P value) {
        return new GenericBuilder<>(() -> {
            T object = supplier.get();
            consumer.accept(object, value);
            return object;
        });
    }

    public T build() {
        return supplier.get();
    }
}    



Post post = GenericBuilder.of(Post::new)
                .with(Post::setTitle, "builder pattern")
                .with(Post::setAuthor, "dachuili")
                .with(Post::setLabel, "design patterns")
                .with(Post::setContent, "classic/generic/lombok builder pattern")
                .build();

Builder模式与抽象类

以下代码来自 Joshua Bloch 的《Effective Java》一书,抽象类有自己的Builder方法, 实现类有自己的 Builder方法。

首先是我们的抽象类 Pizza,定义了一些 topping,也就是Pizza上铺的食材(火腿、蘑菇、洋葱、辣椒、香肠之类的)。

public abstract class Pizza {
    public enum Topping { HAM, MUSHROOM, ONION, PEPPER, SAUSAGE }
    final Set<Topping> toppings;
    Pizza(Builder<?> builder) {
        toppings = builder.toppings.clone();
    }

    abstract static class Builder<T extends Builder<T>> {
        EnumSet<Topping> toppings = EnumSet.noneOf(Topping.class);
        public T addTopping(Topping topping) {
            toppings.add(Objects.requireNonNull(topping));
            return self();
        }
        // Subclasses must override this method to return "this"
        protected abstract T self();

        abstract Pizza build();
    }
}

其中一个实现类是 NyPizza 和 自己的 Builder 实现类,New York Pizza 有不同的size。

public class NyPizza extends Pizza{
    public enum Size { SMALL, MEDIUM, LARGE }
    private final Size size;

    public static class Builder extends Pizza.Builder<Builder>{
        private final Size size;
        public Builder(Size size) {
            this.size = Objects.requireNonNull(size);
        }
        @Override public NyPizza build() {
            return new NyPizza(this);
        }
        @Override protected Builder self() { return this; }
    }

    private NyPizza(Builder builder) {
        super(builder);
        size = builder.size;
    }
}

另一个实现类是 Calzone,搜了下就是这个菜盒子。🤣

不区分大小,但有个属性 sauceInside 代表“是否内部有酱汁”。

public class Calzone extends Pizza{
    private final boolean sauceInside;
    public static class Builder extends Pizza.Builder<Builder>
    {
        private boolean sauceInside = false; // Default
        public Builder sauceInside() {
            sauceInside = true;
            return this;
        }
        @Override public Calzone build() {
            return new Calzone(this);
        }
        @Override protected Builder self() { return this; }

    }
    private Calzone(Builder builder) {
        super(builder);
        sauceInside = builder.sauceInside;
    }
}

创建过程如下:

        NyPizza pizza = new NyPizza.Builder(SMALL)
                .addTopping(SAUSAGE).addTopping(ONION).build();
        Calzone calzone = new Calzone.Builder()
                .addTopping(HAM).sauceInside().build();

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/947527.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【人工智能机器学习基础篇】——深入详解监督学习之模型评估:掌握评估指标(准确率、精确率、召回率、F1分数等)和交叉验证技术

深入详解监督学习之模型评估 在监督学习中&#xff0c;模型评估是衡量模型性能的关键步骤。有效的模型评估不仅能帮助我们理解模型在训练数据上的表现&#xff0c;更重要的是评估其在未见数据上的泛化能力。本文将深入探讨监督学习中的模型评估方法&#xff0c;重点介绍评估指…

Linux(Ubuntu24.04)源码编译安装VTK7.1.1记录

VTK&#xff08;Visualization Toolkit&#xff09;是一个开源的3D可视化开发工具包&#xff0c;用于开发可视化和图形处理应用程序。VTK提供了一系列的算法和工具&#xff0c;用于创建、渲染和处理复杂的3D图形和数据。VTK由C编写&#xff0c;并提供了Python、Java和Tcl等语言…

FICO财务模块在SAP ECC与S4 HANA系统间的差异有哪些?

【SAP系统研究】 #SAP #FICO #ECC #HANA #Oracle #SAP财务 尽管SAP S4/HANA已经发布很久&#xff0c;但使用SAP ECC系统的企业也仍然很多。 这两个系统在FICO模块中有哪些常见的不同呢&#xff1f; 1、数据库表 ①SAP ECC系统 可以在Oracle、IBM DB2等数据库上运行 ②SAP S…

CDPHudi实战-集成spark

[一]使用Spark-shell 1-配置hudi Jar包 [rootcdp73-1 ~]# for i in $(seq 1 6); do scp /opt/software/hudi-1.0.0/packaging/hudi-spark-bundle/target/hudi-spark3.4-bundle_2.12-1.0.0.jar cdp73-$i:/opt/cloudera/parcels/CDH/lib/spark3/jars/; done hudi-spark3.4-bu…

mac m2 安装 docker

文章目录 安装1.下载安装包2.在downloads中打开3.在启动台打开打开终端验证 修改国内镜像地址小结 安装 1.下载安装包 到官网下载适配的安装包&#xff1a;https://www.docker.com/products/docker-desktop/ 2.在downloads中打开 拖过去 3.在启动台打开 选择推荐设置 …

Power BI如何连接Azure Databricks数据源?

故事背景: 近期有朋友询问&#xff0c;自己公司有一些项目使用了Azure Databricks用于数据存储。如何使用Power BI Desktop桌面开发软件连接Azure Databricks的数据源呢&#xff1f; 解决方案: 其实Power BI是提供了连接Azure Databricks数据源的选项的&#xff0c;只是配置…

Python入门教程 —— 进制转换

找其他编译器&#xff0c;系统解释器&#xff0c;这样速度会快很多。 进制 现代的计算机和依赖计算机的设备里都用到二进制(即0和1)来保存和表示数据&#xff0c;一个二进制表示一个比特(Bit)。 在二进制的基础上&#xff0c;计算机还支持八进制和十六进制这两种进制。 除了…

HTML5新特性|05 CSS3边框CSS3背景

CSS3边框 1、CSS3边框: 通过CSS3&#xff0c;您能够创建圆角边框&#xff0c;向矩形添加阴影&#xff0c;使用图片来绘制边框-并且不需使用设计软件&#xff0c;比如PhotoShop。 属性: border-radius 圆角box-shadow:水平阴影 垂直阴影 阴影的清晰度 阴影的大小 阴影的颜色…

《Vue3实战教程》26:Vue3Transition

如果您有疑问&#xff0c;请观看视频教程《Vue3实战教程》

SpringCloudAlibaba实战入门之Sentinel服务降级和服务熔断(十五)

一、Sentinel概述 1、Sentinel是什么 随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。 一句话概括:sentinel即Hystrix的替代品,官网: https://sentinelguard.io/zh…

Scratch教学作品 | 白水急流——急流勇进,挑战反应极限! ‍♂️

今天为大家推荐一款刺激又好玩的Scratch冒险作品——《白水急流》&#xff01;由AgentFransidium制作&#xff0c;这款作品将带你体验惊险的急流救援任务&#xff0c;帮助那位“睡着的疯狂人”安全穿越湍急水域&#xff01;想要挑战自己的反应极限&#xff1f;快来试试吧&#…

计算机毕业设计Django+Tensorflow音乐推荐系统 音乐可视化 卷积神经网络CNN LSTM音乐情感分析 机器学习 深度学习 Flask

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

Nginx服务器配置SSL证书

1.执行以下命令&#xff0c;在Nginx的conf目录下创建一个用于存放证书的目录。 cd /usr/local/nginx/conf #进入Nginx默认配置文件目录。该目录为手动编译安装Nginx时的默认目录&#xff0c;如果您修改过默认安装目录或使用其他方式安装&#xff0c;请根据实际配置调整。 mkd…

Gemini和ChatGPT全面对比分析,有什么区别和优势?

当 AI 聊天机器人首次出现时&#xff0c;每个人都在竞相发布自己的足够好的第一版 AI 聊天机器人&#xff0c;很容易在 Gemini 与 ChatGPT 等应用程序之间进行比较。但随着 Google 和 OpenAI 不断添加新功能、模型和访问其聊天机器人的方式&#xff0c;差异变得不那么明显。 现…

从0到机器视觉工程师(二):封装调用静态库和动态库

目录 静态库 编写静态库 使用静态库 方案一 方案二 动态库 编写动态库 使用动态库 方案一 方案二 方案三 总结 静态库 静态库是在编译时将库的代码合并到最终可执行程序中的库。静态库的优势是在编译时将所有代码包含在程序中&#xff0c;可以使程序独立运行&…

低代码开发:开启企业数智化转型“快捷键”

一、低代码开发浪潮来袭&#xff0c;企业转型正当时 在当今数字化飞速发展的时代&#xff0c;低代码开发已如汹涌浪潮&#xff0c;席卷全球。从国际市场来看&#xff0c;诸多企业巨头纷纷布局低代码领域&#xff0c;像微软的 PowerApps、OutSystems 等平台&#xff0c;凭借强大…

UE5动画蓝图

动画蓝图&#xff0c;混合空间&#xff0c;状态机&#xff0c;瞄准偏移&#xff0c;动画蒙太奇&#xff0c;动画混合&#xff0c;骨骼绑定&#xff0c;动画重定向&#xff0c;动画通知&#xff0c;Control Rig…… 虚幻动画模块是一个庞大的系统&#xff0c;大模块里又包含很多…

[redux] useDispatch的两种用法

先重写2个方法先, 方便ts类型推导,如果你看不懂为什么这么写, 先看我这篇 [redux] ts声明useSelector和useDispatch-CSDN博客 export type RootState ReturnType<typeof store.getState>; export type AppDispatch typeof store.dispatch; export const useAppDispat…

javaEE-网络原理-1初识

目录 一.网络发展史 1.独立模式 2.网络互联 二.局域网LAN 1.基于网线直连&#xff1a; 2.基于集线器组件&#xff1a; 3.基于交换机组件&#xff1a; 4.基于交换机和路由器组件 ​编辑 三、广域网WAN 四、网络通信基础 1.ip地址 2.端口号&#xff1a; 3.协议 4.五…

jenkins入门3

1、新建视图 视图可以理解为是item的集合&#xff0c;这样可以将item分类。新建视频可以选择加入已有的item 2、新建item 1)输入任务名称、选择一个类型&#xff0c;常用的是第一个freestyle project 2&#xff09;进行item相关配置&#xff0c;general 设置项目名字,描述,参数…