假设我们现在有一个Student对象,对象中有两个属性age和score,如下方代码块所示
private int age;
private int score;
思考:如果我们要对对象中的字段进行赋值可以选的方式有哪几种?
1.采用 new 对象并进行set赋值
public static void main(String[] args) {
Student student = new Student();
student.setAge(10);
student.setScore(15);
}
这种赋值方式可以说是最老牌也用的人最多的赋值方式了,不过这种赋值方式有种弊端,就是当实体类字段过多的时候,需要写很多set,代码易读性大大降低
//例
Student student = new Student();
student.setAge(10);
student.setScore(15);
student.setAge(10);
student.setScore(15);
student.setAge(10);
student.setScore(15);
student.setAge(10);
student.setScore(15);
student.setAge(10);
student.setScore(15);
student.setAge(10);
student.setScore(15);
student.setAge(10);
student.setScore(15);
2.采用对象类中设置赋值方法,并通过new Student(x,x)的方式进行赋值
//在Student类中添加如下方法
Student(int age, int score){
super();
this.age = age;
this.score = score;
}
//赋值
Student student = new Student(10,20);
使用这种方法,字段顺序必须保证正确,并且无用的值也需要进行设置,容易产生冗余工作。对于代码的读者来说,也很难去对应各个属性值代表的意思
//例:当我们只想给age字段赋值,score字段不用赋值时
Student student = new Student(10,null);
3.通用Builder构造器赋值
//例
Student student = Builder.of(Student::new)
.with(Student::setAge, 10)
.with(Student::setScore, 15)
.build();
可以看到,构造器使用的是流式编程,整个赋值过程简洁易懂。但是这种赋值方式在同一个对象需要在不同的位置针对不同的字段进行赋值时,使用体验几乎为零
3.1使用通用Builder构造器进行赋值的话,需要在项目种添加Builder类(如下),添加之后即可像上面的例子一样进行使用
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;
/**
* @program: practice
* @description: 通用Build构造器
* @author: ID-Tang
* @create: 2021-03-31 09:31
**/
public class Builder<T> {
private final Supplier<T> instantiator;
private List<Consumer<T>> modifiers = new ArrayList<>();
private Builder(Supplier<T> instantiator) {
this.instantiator = instantiator;
}
public static <T> Builder<T> of(Supplier<T> instantiator) {
return new Builder<>(instantiator);
}
public <P1> Builder<T> with(Consumer1<T, P1> consumer, P1 p1) {
Consumer<T> c = instance -> consumer.accept(instance, p1);
modifiers.add(c);
return this;
}
public <P1, P2> Builder<T> with(Consumer2<T, P1, P2> consumer, P1 p1, P2 p2) {
Consumer<T> c = instance -> consumer.accept(instance, p1, p2);
modifiers.add(c);
return this;
}
public <P1, P2, P3> Builder<T> with(Consumer3<T, P1, P2, P3> consumer, P1 p1, P2 p2, P3 p3) {
Consumer<T> c = instance -> consumer.accept(instance, p1, p2, p3);
modifiers.add(c);
return this;
}
public T build() {
T value = instantiator.get();
modifiers.forEach(modifier -> modifier.accept(value));
modifiers.clear();
return value;
}
/**
* 1 参数 Consumer
*/
@FunctionalInterface
public interface Consumer1<T, P1> {
void accept(T t, P1 p1);
}
/**
* 2 参数 Consumer
*/
@FunctionalInterface
public interface Consumer2<T, P1, P2> {
void accept(T t, P1 p1, P2 p2);
}
/**
* 3 参数 Consumer
*/
@FunctionalInterface
public interface Consumer3<T, P1, P2, P3> {
void accept(T t, P1 p1, P2 p2, P3 p3);
}
}
4.采用链式编程方式进行赋值
链式编程需要在实体类上添加@Accessors(chain = true)
注解,该注解的意思是开启链式编程
//示例
@Data
@Accessors(chain = true)
public class Student {
private int age;
private int score;
}
上面的示例即已开启链式编程,在对实体类进行赋值时,可以使用.set
的方式进行追加赋值
//示例
public static void main(String[] args) {
Student student = new Student()
.setAge(10)
.setScore(10);
}
采用该赋值方式,需要在每个新建的实体类上都加入@Accessors(chain = true)
注解,而使用Builder构造器进行赋值,只用引入一次Builder
类即可实现任何地方无差别使用
链式编程和通用Builder构造器赋值对比
//链式编程
Student student = new Student()
.setAge(10)
.setScore(10);
//通用Builder构造器
Student build = Builder.of(Student::new)
.with(Student::setAge, 10)
.with(Student::setScore, 15)
.build();
萝卜青菜各有所爱,没有什么方式是最优解,跟随自己的心,用自己最喜欢的方式就好~