当前位置: 首页 > article >正文

建造者模式 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();

http://www.kler.cn/a/464826.html

相关文章:

  • 融合表面信息和等变扩散的分子对接模型 SurfDock - 评测
  • 计算机网络练习题
  • Linux菜鸟级常用的基本指令和基础知识
  • CSS——1.优缺点
  • ETCD渗透利用指南
  • 论文泛读《LPFHE: Low-Complexity Polynomial CNNs for Secure Inference over FHE》
  • docker下载redis,zookeeper,kafka超时time out
  • 软件工程大复习(五) 需求工程与需求分析
  • Linux系统安装es详细教程
  • 【IEEE冠名会议】2025年IEEE第二届深度学习与计算机视觉国际会议(DLCV 2025)
  • Go recover的执行时机
  • 剪映--关键帧教程:制作视频文字说明,文字动态划线,透明文字,虚拟触控,画面旋转缩小退出
  • TCP IP 网络协议基础入门 1
  • 加速开发体验:为 Android Studio 设置国内镜像源
  • VSCode函数调用关系图插件开发(d3-graphviz)
  • Git核心概念总结
  • 2022浙江大学信号与系统笔记
  • 小程序租赁系统的优势与应用探索
  • Android笔试面试题AI答之Android基础(11)
  • BFS中的双向广搜和A-star
  • 深入理解 PHP 构造函数和析构函数:附示例代码
  • 【JVM】JVM自学笔记(类加载子系统、运行时数据区、执行引擎)
  • Python世界:高频小技巧总结
  • 低代码开发:开启企业数智化转型“快捷键”
  • Python 图像处理:生成美丽的书籍封面
  • torch.nn.functional的用法