在java中,对于类中属性赋值,大部分情况下会使用set,get,可能还有些boolean的属性有些框架会用is做为前缀。但是对于一个类中有多个参数,总不能set多个参数或者构造函数中写多个参数的构造吧。在idea中生成构造函数和set/get方法都是有快捷方式的,但是在使用的时候就痛苦了。
对于这个问题,有没有什么好的解决方法呢?
《effective java》中推荐使用bulder模式
/** * 使用Builder模式 */ public class Person { //必要参数 private final int id; private final String name; //可选参数 private final int age; private final String sex; private final String phone; private final String address; private final String desc; private Person(Builder builder) { this.id = builder.id; this.name = builder.name; this.age = builder.age; this.sex = builder.sex; this.phone = builder.phone; this.address = builder.address; this.desc = builder.desc; } public static class Builder { //必要参数 private final int id; private final String name; //可选参数 private int age; private String sex; private String phone; private String address; private String desc; public Builder(int id, String name) { this.id = id; this.name = name; } public Builder age(int val) { this.age = val; return this; } public Builder sex(String val) { this.sex = val; return this; } public Builder phone(String val) { this.phone = val; return this; } public Builder address(String val) { this.address = val; return this; } public Builder desc(String val) { this.desc = val; return this; } public Person build() { return new Person(this); } }
public static void main(String[] args) { Person person = new Person.Builder(1, "张三") .age(18).sex("男").desc("测试使用builder模式").build(); System.out.println(person.toString()); }
}
而另一种方式的实现为
public class Person { //必要参数 private int id; private String name; //可选参数 private int age; private String sex; private String phone; private String address; private String desc; public Person() { } public Person id(int id) { this.id = id; return this; } public Person age(int age) { this.age = age; return this; } public Person name(String name) { this.name = name; return this; } public Person sex(String sex) { this.sex = sex; return this; } public Person phone(String phone) { this.phone = phone; return this; } public Person address(String address) { this.address = address; return this; } public Person desc(String desc) { this.desc = desc; return this; } @Override public String toString() { return "Person{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + ", sex='" + sex + '\'' + ", phone='" + phone + '\'' + ", address='" + address + '\'' + ", desc='" + desc + '\'' + '}'; }
public static void main(String[] args) { Person person = new Person() .id(12) .name("tom") .age(12) .desc("abc"); }}
第二种和第一种有几点不同:
1)第一种需要引入builder类,而且还需要把Person类里面的字段再copy一份,我们都知道类的信息放在方法区,在堆中对它有指向的引用而已。这样每次添加一个类(当然不可能每次类都有这么多字段,使用这种builder模式),就要增加一个类信息的bulder,肯定需要占内存,这个地方可能内存泄漏(当然还是有点夸张,毕竟就几个这样的类,而且在jdk8中,类信息放在了metaspace,移到了堆中,并且还是自动扩容的,说这么多就是想说第二种好)
2)第二种在使用的时候是先用了一个默认的构造函数,对象已经产生,如果后续校验出错的话,之后的函数方法都不会调用。第一种方法,如果在builder的时候,校验出错,对象创建不成功!第一种不占资源。不过貌似这样的场景不多,一般程序员都知道怎么正确的创建自己写的类对象。强行算第一种胜出!
3)第二种写比第一种写很方便!
4)如果说第一种是线程安全的,第二种类也可以用final修饰。而且在使用的时候,创建出来的对象,一般都是放在方法体里面执行,每个方法生成一个帧栈,都是线程独享的。对象不可达时,下次发生gc就会自动回收。所以考虑大部分应用场景,第二种更胜一筹!
感觉第二种实现方式比第一种好!还是想多了,第二种是builder的变异版本,jdk8 的stream----系统方法不都是这样的吗!
注:它们单线程中使用没任何问题!
学而不思则罔,思而不学则殆!