学了这个,三歪再也不想写各种setter了

简介: 今天又来给大家吹一下逼。三歪在公司里边也看了不少的系统了,看到结构清晰、代码清晰的系统时会赞叹能写出这种代码的人是真的牛逼。看到乱七八糟的代码又不写注释的时候也会吐槽:“这写的是啥啊”

今天又来给大家吹一下逼。

三歪在公司里边也看了不少的系统了,看到结构清晰、代码清晰的系统时会赞叹能写出这种代码的人是真的牛逼。看到乱七八糟的代码又不写注释的时候也会吐槽:“这写的是啥啊”

多看别人的代码,总会有不同的发现和体会。

最近看别人项目的时候,发现会有这种写法:

MessageTask task = MessageTask.builder()
  .content("关注 Java3y 吧 >> ")
  .messageId(String.valueOf(ThreadLocalRandom.current().nextLong()))
  .taskId("3y")
  .taskName("一起来玩")
  .build();
System.out.println(task.toString());

看代码其实很容易看出它在干嘛,就是在创建MessageTask这个对象。

平时我们初学的时候,如果要创建这个对象会怎么写?一般会有两种方法:

  1. 将属性配在构造函数上,然后直接调构造器,传入参数
  2. 调用多个set方法
// 构造器传入属性
MessageTask messageTask = new MessageTask("3y", "关注 Java3y 吧 >>", 
                                          String.valueOf(ThreadLocalRandom.current().nextLong()), "一起来玩");
// 调用各种的set方法
MessageTask messageTask = new MessageTask();
messageTask.setTaskId("3y");
messageTask.setContent("关注 Java3y 吧 >>");
messageTask.setMessageId(String.valueOf(ThreadLocalRandom.current().nextLong()));
messageTask.setTaskName("一起来玩");

日常使用的话,应该是多次调用set方法比较多的(应该都是这样的吧)。

从代码层面上,构造器传参的代码是最简短的,但在现实层面上我们很难每次都可以通过构造器传参的方式去完成对象的创建(更多的时候每个对象的属性都是不一致的)。

构造器的代码看起来非常短,但阅读起来不太友好(我得去看每个参数是什么意思);

set方法写起来不太方便,如果对象的属性较多,也会有一大串的set代码。

而文章最开始的builer链式调用就很舒服,我一看这代码就知道这肯定是哪种我不知道的设计模式。

于是我一查,原来这就叫做建造者模式


怎么实现建造者模式?


建造者模式更多的是写法上的不同,从代码结构层面上其实没有很大的区别,只是看起来会更清爽一些。

那怎么实现建造者模式呢?其实也非常简单:

  • 在domain类上创建一个静态内部类 Builder,Builder拥有domain所有的属性
  • 在domain类上创建一个private的构造函数,参数为Builder类型,里边将Builder的属性赋值给domain的属性
  • 在Builder内部类创建domain属性的赋值方法,返回值是Builder
  • Builder内部类创建一个build方法,返回domain实例

下面我们来实现一下吧,首先创建一个静态内部类Builder,并且内部类Builder拥有domain的所有属性:

public class MessageTask {
    private String taskId;
    private String content;
    private String messageId;
    private String taskName;
   // 创建内部类
    public static class Builder{
        private String taskId;
        private String content;
        private String messageId;
        private String taskName;
    }
}

在domain类上创建一个private的构造函数,参数为Builder类型,里边是将Builder的属性赋值给domain的属性:

public class MessageTask {
    private String taskId;
    private String content;
    private String messageId;
    private String taskName;
   // 增加private构造函数
    private MessageTask(Builder builder) {
        this.taskId = builder.taskId;
        this.content = builder.content;
        this.messageId = builder.messageId;
        this.taskName = builder.taskName;
    }
    public static class Builder{
        private String taskId;
        private String content;
        private String messageId;
        private String taskName;
    }
}

在Builder内部类创建domain属性的赋值方法,返回值是Builder

public class MessageTask {
    private String taskId;
    private String content;
    private String messageId;
    private String taskName;
    private MessageTask(Builder builder) {
        this.taskId = builder.taskId;
        this.content = builder.content;
        this.messageId = builder.messageId;
        this.taskName = builder.taskName;
    }
    public static class Builder{
        private String taskId;
        private String content;
        private String messageId;
        private String taskName;
        // 赋值属性的方法(返回的是Builder)
        public Builder setTaskId(String taskId) {
            this.taskId = taskId;
            return this;
        }
        public Builder setContent(String content) {
            this.content = content;
            return this;
        }
        public Builder setMessageId(String messageId) {
            this.messageId = messageId;
            return this;
        }
        public Builder setTaskName(String taskName) {
            this.taskName = taskName;
            return this;
        }
    }
}

在Builder内部类创建一个builde方法,返回domain实例

public class MessageTask {
    private String taskId;
    private String content;
    private String messageId;
    private String taskName;
    private MessageTask(Builder builder) {
        this.taskId = builder.taskId;
        this.content = builder.content;
        this.messageId = builder.messageId;
        this.taskName = builder.taskName;
    }
    public static class Builder{
        private String taskId;
        private String content;
        private String messageId;
        private String taskName;
        public Builder setTaskId(String taskId) {
            this.taskId = taskId;
            return this;
        }
        public Builder setContent(String content) {
            this.content = content;
            return this;
        }
        public Builder setMessageId(String messageId) {
            this.messageId = messageId;
            return this;
        }
        public Builder setTaskName(String taskName) {
            this.taskName = taskName;
            return this;
        }
    // 创建build方法,返回实例
        public MessageTask build() {
            return new MessageTask(this);
        }
    }
}

使用方式:先创建Builder对象,然后用Builder去赋值,最后再调用build()返回真正的实例:

MessageTask.Builder builder = new MessageTask.Builder();
MessageTask task = builder.setContent("关注 Java3y 吧 >>")
  .setTaskId("3y")
  .setTaskName("一起来玩")
  .setMessageId(String.valueOf(ThreadLocalRandom.current().nextLong()))
  .build();


借助工具使用建造者模式


从使用的角度感觉是好用了,代码也清爽了。其实可以发现的是,我们都把逻辑写到了Domain类上,这写起来肯定是需要花时间的。

我第一印象是:这种这么通用的东西,肯定是有可以一键生成的方法的,于是我瞄准了Lombok

果不其然,我们如果使用了Lombok后,在类上加上一个注解@Builder就可以使用建造者模式的代码了,非常方便

@Builder
@Data
public class MessageTask {
    private String taskId;
    private String content;
    private String messageId;
    private String taskName;
}

又想了一下,IDEA这么强大,感觉IDEA也有办法去生成Builder,也果不其然:

35.jpg

做个小调查:

  • 如果你之前已经了解过了建造者模式,你在项目中有用吗?
  • 如果你看了这篇文章才了解到了建造者模式,你在以后会用吗?

我个人是看团队的代码风格的,如果原有已经是各种set去构造对象,那我就不会再修改了。如果是新写的业务,会使用建造者模式。


目录
相关文章
|
2月前
|
数据采集 大数据 Python
学Python静不下来,看了一堆资料还是很迷茫是为什么
学Python静不下来,看了一堆资料还是很迷茫是为什么
40 2
学Python静不下来,看了一堆资料还是很迷茫是为什么
|
11月前
|
设计模式 JSON 监控
趣谈装饰器模式,让你一辈子不会忘
来看这样一个场景,上班族大多有睡懒觉的习惯,每天早上上班都时间很紧张,于是很多人为了多睡一会儿,就用更方便的方式解决早餐问题,有些人早餐可能会吃煎饼。煎饼中可以加鸡蛋,也可以加香肠,但是不管怎么加码,都还是一个煎饼。再比如,给蛋糕加上一些水果,给房子装修,都是装饰器模式。
71 0
|
10月前
|
设计模式 网络协议 算法
|
10月前
|
设计模式 缓存 算法
花了30天才肝出来,史上最全面Java设计模式总结,看完再也不会忘
Design Patterns: Elements of Reusable Object-Oriented Software(以下简称《设计模式》),一书由Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides合著(Addison-Wesley,1995)。这四位作者常被称为“四人组(Gang of Four)”,而这本书也就被称为“四人组(或 GoF)”书。他们首次给我们总结出一套软件开发可以反复使用的经验,帮助我们提高代码的可重用性、系统的可维护性等,解决软件开发中的复杂问题。
126 0
|
IDE 开发工具 Python
这样的奇技淫巧,劝你不用也罢
这样的奇技淫巧,劝你不用也罢
113 0
有点迷糊的题
2541. 使数组中所有元素相等的最小操作数 II - 力扣(LeetCode)
53 0
|
JavaScript 前端开发 小程序
程序员过中秋的一百种方式#
程序员过中秋的正确方式:团圆、赏月、还是惨兮兮地加班? 赏月 明月几时有,把酒问青天
153 0
程序员过中秋的一百种方式#
|
算法 NoSQL API
到底该不该看源码(懂这三点儿就够了)
1、不要为了看源码而看源码 2、代码积累到一定程度,遇到问题自然就去查源码了,然后你就看懂了 3、两年内不要刻意去看源码,可以点开简单了解一下就行,前两年疯狂做项目就行了,后期项目做的多了,你自己就会有疑问,每次写代码就会问自己为什么要这样写?底层的原理是什么?很自觉的带着问题就去看源码了,如果你没有这样的疑问,那说明你也不适合去看源码了,写写业务代码,了了一生
159 0
|
JavaScript 前端开发
不看后悔系列!原来代码还可以这么写!
不看后悔系列!原来代码还可以这么写!
|
存储 算法 安全
烧点脑子使劲看--对象详细讲解
当Java虚拟机遇到一条new字节码指令时,首先会检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并检查这个符号引用所代表的类是否已经被加载,如果没有,就必须先将就该类加载到内存中,具体过程见:
81 0