同事写了一个疯狂的类构造器,我要疯了,Builder 模式都不会么?!

疯狂的类构造器

最近栈长在做 Code Review 时,发现一段创建对象的方法:

Task task = new Task(112, "紧急任务", "处理一下这个任务", 90, 3, 1, 36, "刘主管", 18, "客服1", "11, 12, 13", "客服3, 客服4, 客服5", true, new Date(), new Date(), new Date(), new Date(), new Date(), 0, "需要尽快完成", ...);

真实代码敏感性,上面的代码仅为模仿,实际要比这个更长、更复杂……

当我看到那段代码时,我简直要疯了!!

拖了半天才看完,到处充满着魔法值不说,把一个类所有参数都放在一个构造器里面,这个构造器也太疯狂了……这种写法也实在太 low 了!

在实际开发过程中,栈长经常看到同事们这样的写法,比上面的更长的构造器你见过没?我反正见过!

一方面,也许他们真不知道怎么写才更好,毕竟经验有限,这个可以原谅。但另一方面,也许他们就是为了偷懒,或者为了赶时间,反正这都是对自己和同事不负责的表现。

如果你在公司看到同事写这样的优秀代码,请把这篇文章发给他。

看看大量参数构造器的缺点:

参数过多时,代码太长,极不优雅,维护极难;

不能判断出哪些是必须参数,哪些是可选参数,可选参数也得给个默认值;

分不清变量值对应哪个变量,如顺序对应错,很容易造成错误;

构造器参数增减时,会影响所有创建该对象的地方,影响扩展性;

构造器正确的用法是只给出几个必选、重要参数的构造器,而不是把所有参数放在一个构造器中。

比如我们看下 JDK 线程池的构造器用法:

同事写了一个疯狂的类构造器,我要疯了,Builder 模式都不会么?!

线程池就把几个重要的参数封装成了几个构造器,这样用户就可以根据实际需要调用具体的某个构造器。

基本 SET 方法改良

再回到同事写的那个代码,写出那样长的构造器,我真的服了。

最基本也得写成这样吧:

Task task = new Task(); task.setId(112); task.setName("紧急任务"); task.setContent("处理一下这个任务"); task.setParentId(90); task.setType(3); task.setLevel(1); task.setAssignFromId(36); task.setAssignFromName("刘主管"); task.setAssignTo(18); task.setAssignTo("客服1"); task.setCandidateId("11, 12, 13"); task.setCandidateName("客服3, 客服4, 客服5"); task.isSendEmail(true); task.setCreateTime(new Date()); task.setBeginTime(new Date()); task.setEndTime(new Date()); task.setFinishTime(new Date()); task.setUpdateTime(new Date()); task.setStatus(0); task.setMemo("需要尽快完成"); // ...

这个创建对象的方式是最普通不过了,也是用的最多的了。

这种写法虽然看起来很直观,但是有以下几个缺点:

参数多的情况下 setter 非常多,代码非常长,不是很优雅;

不能判断出哪些是必须参数,哪些是可选参数;

容易漏掉一些参数,并且很难检查出来;

容易搞错对象名,造成潜在错误,很难排查(如:同时有 user 和 user2,在 user 赋值过程中错误的复制了 user2 对象);

Builder 模式改良

下面栈长教大家用 Builder 模式改良下,下面是改良后的代码:

package cn.javastack.test.designpattern.builder; import java.util.Date; /** * @author: 栈长 * @from: 公众号Java技术栈 */ public class Task { private long id; private String name; private String content; private int type; private int status; private Date finishDate; private Task(TaskBuilder taskBuilder) { this.id = taskBuilder.id; this.name = taskBuilder.name; this.content = taskBuilder.content; this.type = taskBuilder.type; this.status = taskBuilder.status; this.finishDate = taskBuilder.finishDate; } /** * @author: 栈长 * @from: 公众号Java技术栈 */ public static class TaskBuilder { private long id; private String name; private String content; private int type; private int status; private Date finishDate; public TaskBuilder(long id, String name) { this.id = id; this.name = name; } public TaskBuilder content(String content) { this.content = content; return this; } public TaskBuilder type(int type) { this.type = type; return this; } public TaskBuilder status(int status) { this.status = status; return this; } public TaskBuilder finishDate(Date finishDate) { this.finishDate = finishDate; return this; } public Task build(){ return new Task(this); } } public long getId() { return id; } public String getName() { return name; } public String getContent() { return content; } public int getType() { return type; } public int getStatus() { return status; } public Date getFinishDate() { return finishDate; } @Override public String toString() { return "Task{" + "id=" + id + ",\'' + ", content='" + content + '\'' + ", type=" + type + ", status=" + status + ", finishDate=" + finishDate + '}'; } }

说下简单思路:

1)在 Bean 类里面新建一个静态内部类:XxxBuilder;

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wspxss.html