我在一个构造方法中写了30个参数,老板看了想骂人

开发 前端
一般我们写参数如果写个一两个,那就可以了,如果写七八个,那就有点难受了。如果写十几个?难受,我要去缓缓。

[[386824]]

前言

一般我们写参数如果写个一两个,那就可以了,如果写七八个,那就有点难受了。如果写十几个?尼玛,难受,我要去缓缓。

于是乎,一种新的方法策略运用而生。那就是builder模式,在构造方法的参数过多时,可以方便的进行创建一个类对象。所以本文的中心主旨一句话总结:当构造方法的参数过多时,推荐使用builder模式

既然推荐使用builder模式,那我们一个一个来,分析一下如果不使用builder模式有什么缺点。

一、传统方式的缺点

1、可伸缩构造方法

可伸缩构造方法就是我们平时书写最常见的那种,请看下文代码;

  1. public class Student { 
  2.  private int id; //必要 
  3.  private String name;//必要 
  4.  private int age; //可选 
  5.  private int sclass; //可选 
  6.  private int height;//可选 
  7.  private float weight;//可选 
  8.  private float score;//可选 
  9.  //构造函数1:默认构造方法 
  10.  public Student() {}; 
  11.  //构造方法2:必要字段构造方法 
  12.  public Student(int id, String name) { 
  13.   this.id = id; 
  14.   this.name = name
  15.  } 
  16.  //构造方法3:全部字段构造方法 
  17.  public Student(int id, String nameint age, int sclass, int height, float weight, float score) { 
  18.   super(); 
  19.   this.id = id; 
  20.   this.name = name
  21.   this.age = age; 
  22.   this.sclass = sclass; 
  23.   this.height = height; 
  24.   this.weight = weight; 
  25.   this.score = score; 
  26.  } 

下面如果我们要创建一个Student类,一般这样创建,看下面代码:

  1. public class Main { 
  2.  public static void main(String[] args) { 
  3.   //1、可伸缩构造方法 
  4.   Student student1 = new Student(); 
  5.   Student student2 = new Student(1,"愚公要移山"); 
  6.   Student student3 = new Student(2,"愚公要移山",18,1,175,120,99); 
  7.  } 

现在我们列举了一个具有七个字段的例子,比较容易理解,现在我们来分析一下,他有什么缺点:

缺点1:反转字段,编译器不会报错

比如上面的字段里面有一个weight和一个score,都是float类型,如果再new一个Student类时,不小心写反了,编译器不会察觉。

缺点2:难以理解

这里只是七个字段,如果有十几个,我们就需要不断地去Student类中去查看,看看第几个参数应该写哪些东西,实在是比较麻烦。用户在看到这个Student(2,"愚公要移山",18,1,175,120,99)无法理解每一个字段属性代表的是什么含义。

缺点3:不想设置的参数,却不得不设置值

有时候我们的Student只想着设置ID、name和age字段,其他的无关紧要,但是这种模式必须要设置所有的属性值。

既然上面有这些缺点,我们可能还想到另外一种方式,那就是javaBean。

2、javaBean模式

先看javaBean模式如何写的。

  1. public class Student { 
  2.  private int id; //必要 
  3.  private String name;//必要 
  4.  private int age; //可选 
  5.  private int sclass; //可选 
  6.  private int height;//可选 
  7.  private float weight;//可选 
  8.  private float score;//可选 
  9.  //构造函数1:默认构造方法 
  10.  public Student() {} 
  11.     //getter和setter方法 
  12.  public int getId() {return id;} 
  13.  public void setId(int id) {this.id = id;} 
  14.  public String getName() {return name;} 
  15.  public void setName(String name) {this.name = name;} 
  16.  public int getAge() {return age;} 
  17.  public void setAge(int age) {this.age = age;} 
  18.  public int getSclass() {return sclass;} 
  19.  public void setSclass(int sclass) {this.sclass = sclass;} 
  20.  public int getHeight() {return height;} 
  21.  public void setHeight(int height) {this.height = height;} 
  22.  public float getWeight() {return weight;} 
  23.  public void setWeight(float weight) {this.weight = weight;} 
  24.  public float getScore() {return score;} 
  25.  public void setScore(float score) {this.score = score;}; 

这种模式,看起来还比较舒服,只是设置了相应的getter和setter方法。再来看看如何使用这种方式去new一个Student类。

  1. public class Main { 
  2.  public static void main(String[] args) { 
  3.   //2、javaBean模式 
  4.   Student student1 = new Student(); 
  5.   student1.setId(1); 
  6.   student1.setName("愚公要移山"); 
  7.   student1.setSclass(1); 
  8.   student1.setWeight(180); 
  9.   student1.setHeight(175); 
  10.   student1.setScore(100); 
  11.   student1.setAge(20); 
  12.  } 

这样看起来还可以,不过这只是我自己一个一个敲出来的。实际在用的时候就知道同样恶心了,现在来总结一波他的缺点。

缺点1:构造过程中 JavaBean可能处于不一致的状态

JavaBeans 模式本身有严重的缺陷。由于构造方法在多次调用中被分割,所以在构造过程中 JavaBean 可能处于不一致的状态。该类没有通过检查构造参数参数的有效性来执行一致性的选项。在不一致的状态下尝试使用对象可能会导致与包含 bug 的代码大相径庭的错误,因此很难调试。

说一下我对其的理解,在上面的例子中,我们的student1对象被多次调用了set方法,但是可能有时候在用到这个bean时,剩下的setter方法还没有做完,于是再次调用时发现同一个javaBean呈现出了两种状态。于是处于一种不一致的状态。

缺点2:无法保证javaBean的不可变性

使用第一种模式可伸缩构造方法实例化之后不会更改可变性,所有的数据都是确定好了的。也可以保证线程安全。但是提供了setter方法,就不能保证了。比如:

  1. public class Main { 
  2.  public static void main(String[] args) { 
  3.   //2、javaBean模式 
  4.   Student student1 = new Student(); 
  5.   student1.setId(1); 
  6.   student1.setName("愚公要移山"); 
  7.   student1.setSclass(1); 
  8.   student1.setWeight(180); 
  9.   student1.setHeight(175); 
  10.   student1.setScore(100); 
  11.   student1.setAge(20); 
  12.   System.out.println(student1.getName()); 
  13.   student1.setName("冯冬冬"); 
  14.   System.out.println(student1.getName()); 
  15.  } 
  16. //输出结果:愚公要移山  冯冬冬 

可以看到,我们可以对Student对象设置多次name,前后是不一致的状态。

既然前面两种都存在各种各样的问题。现在我们再来看今天的主题builder模式,

二、builder模式

还是老样子,我们先看看builder模式长得什么样子。再来分析一下他的优缺点。

  1. public class Student { 
  2.  private int id; // 必要 
  3.  private String name;// 必要 
  4.  private int age; // 可选 
  5.  private int sclass; // 可选 
  6.  private int height;// 可选 
  7.  private float weight;// 可选 
  8.  private float score;// 可选 
  9.  public Student(Builder builder) { 
  10.   this.id = builder.id; 
  11.   this.name = builder.name
  12.   this.age = builder.age; 
  13.   this.sclass = builder.sclass; 
  14.   this.height = builder.height; 
  15.   this.weight = builder.weight; 
  16.   this.score = builder.score; 
  17.  } 
  18.  public static class Builder { 
  19.   private int id; // 必要 
  20.   private String name;// 必要 
  21.   private int age; // 可选 
  22.   private int sclass; // 可选 
  23.   private int height;// 可选 
  24.   private float weight;// 可选 
  25.   private float score;// 可选 
  26.   // 必要参数的构造方法 
  27.   public Builder(int id, String name) { 
  28.    this.id = id; 
  29.    this.name = name
  30.   } 
  31.   public Builder setId(int id) { 
  32.    this.id = id; 
  33.    return this; 
  34.   } 
  35.   public Builder setName(String name) { 
  36.    this.name = name
  37.    return this; 
  38.   } 
  39.   public Builder setAge(int age) { 
  40.    this.age = age; 
  41.    return this; 
  42.   } 
  43.   public Builder setSclass(int sclass) { 
  44.    this.sclass = sclass; 
  45.    return this; 
  46.   } 
  47.   public Builder setHeight(int height) { 
  48.    this.height = height; 
  49.    return this; 
  50.   } 
  51.   public Builder setWeight(float weight) { 
  52.    this.weight = weight; 
  53.    return this; 
  54.   } 
  55.   public Builder setScore(float score) { 
  56.    this.score = score; 
  57.    return this; 
  58.   } 
  59.   // 对外提供的 
  60.   public Student build() { 
  61.    return new Student(this); 
  62.   } 
  63.  } 

上面的代码是在内部构造了一个Builder类,然后我们看看如何去使用。

  1. public class Main { 
  2.  public static void main(String[] args) { 
  3.   //3、Builder模式 
  4.   Student stu = new Student.Builder(1, "愚公要移山"
  5.     .setAge(20) 
  6.     .setHeight(175) 
  7.     .setSclass(1) 
  8.     .setScore(100) 
  9.     .setWeight(100).build(); 
  10.  } 

这本书中对其的缺点也进行了介绍,很直观可以看到,Student类中的代码量增加了很多。但是Student类,我们只需要写一次,这却为我们创建对象带来了方便。

优点1:不存在反转字段的情况

上面可以看出,每次添加新字段值的时候是通过set方式进行的。具有javaBean的优点。

优点2:灵活构造参数

我们把必要的字段一写,那些非必要的字段我们可以自己选择是不是要set。

优点3:不存在不一致状态

使用builder模式,对象的创建必须要等到build完成才可以。

优点4:使用灵活

单个 builder 可以重复使用来构建多个对象。builder 的参数可以在构建方法的调用之间进行调整,以改变创建的对象。builder 可以在创建对象时自动填充一些属性,例如每次创建对象时增加的序列号。

缺点:

为了创建对象,首先必须创建它的 builder。虽然创建这个 builder 的成本在实践中不太可能被注意到,但在性能关键的情况下可能会出现问题。而且,builder 模式比伸缩构造方法模式更冗长,因此只有在有足够的参数时才值得使用它,比如四个或更多。

但是,如果从构造方法或静态工厂开始,并切换到 builder,当类演化到参数数量失控的时候,过时的构造方法或静态工厂就会面临尴尬的处境。因此,所以,最好从一开始就创建一个 builder。

总结

如果我们的参数比较多时,builder模式是一个不错的选择,如果比较少时,由于Builder本身也是个对象占用一定的资源,所以还是使用可伸缩或者是javaBean的那种模式比较好。

本文转载自微信公众号「 愚公要移山」,作者冯冬冬 。转载本文请联系愚公要移山公众号。

 

责任编辑:武晓燕 来源: 愚公要移山
相关推荐

2020-12-28 05:54:37

构造builder模式

2021-08-16 13:51:35

开发语言脚本

2021-06-07 10:20:31

2021-02-20 07:52:35

防猝死插件 IDEA

2021-02-02 11:59:15

插件开发工具

2020-11-02 08:19:18

RPC框架Java

2020-03-03 07:59:29

设计秒杀系统

2012-12-07 10:04:58

管理项目管理日常管理

2020-08-04 16:56:50

Java方法参数

2013-05-13 10:24:44

谷歌开发团队开发管理

2023-12-28 08:01:59

2019-09-18 09:41:25

亿级流量网站

2021-08-12 00:03:37

JSStrview视图

2020-08-25 20:10:53

GitHub代码开发者

2022-03-24 07:57:58

Python水果忍者游戏

2009-09-02 18:36:46

LinuxLinux操作系统Linux开发

2010-07-07 16:21:40

重用

2022-02-25 08:25:25

程序开发代码

2020-06-28 08:10:00

GoGOSSAFUNC图编程语言

2020-05-15 09:30:12

代码函数语言
点赞
收藏

51CTO技术栈公众号