在平时开发中,我们经常需要去new一个对象。如果一个类的属性很多,就要设置较多的setXXX,这样实例化和赋值分开,较为分散。
一般情况下,Builder方式可以完成流式风格的赋值方式,比如Guava的CacheBuilder,如:
CacheBuilder.newBuilder()
.maximumSize(10000)
.expireAfterAccess(2, TimeUnit.MINUTES)
.expireAfterWrite(10, TimeUnit.MINUTES)
.initialCapacity(100)
.build();
又如Curator中的:
CuratorFramework curatorFramework = CuratorFrameworkFactory.
builder().
connectString(server.getConnectString()).
sessionTimeoutMs(1000).
retryPolicy(new RetryNTimes(3, 1000)).
build();
本文给出三种方式去完成Builder方式的构建:
01
▼
写对应的Builder类
import java.util.List;
public class Book {
private String name;
private String isbn;
private List<String> authors;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
public List<String> getAuthors() {
return authors;
}
public void setAuthors(List<String> authors) {
this.authors = authors;
}
@Override
public String toString() {
return "Book [name=" + name + ", isbn=" + isbn + ", authors=" + authors + "]";
}
}
import java.util.List;
public class BookBuilder {
private String name;
private String isbn;
private List<String> authors;
public static BookBuilder newInstance() {
return new BookBuilder();
}
public BookBuilder name(String name) {
this.name = name;
return this;
}
public BookBuilder isbn(String isbn) {
this.isbn = isbn;
return this;
}
public BookBuilder authors(List<String> authors) {
this.authors = authors;
return this;
}
public Book build() {
Book book =new Book();
book.setAuthors(authors);
book.setName(name);
book.setIsbn(isbn);
return book;
}
}
Book book = BookBuilder.newInstance().name("Hello java")
.isbn("1234567890").authors(Arrays.asList("Eric"))
.build();
// Book [name=Hello java, isbn=1234567890, authors=[Eric]]
System.out.println(book);
02
▼
使用Lombok
根据Lombok官网https://projectlombok.org/的介绍如下:
Project Lombok is a java library that automatically plugs into
your editor and build tools, spicing up your java.
Never write another getter or equals method again,
with one annotation your class has a fully featured builder,
Automate your logging variables, and much more.
根据Lombok官网的描述可以看出:
Project Lombok是一个java库,其可以自动插入到你的编辑器和构建工具中,
使java代码更加生动。
使用Lombok提供的注解将会带来诸多改变,如:
-- 不需要再写getter、equals等方法
-- 一个注解将为类提供功能齐全的Builder,后续我们将会演示@Builder注解
-- 自动插入日志变量等等
针对本文,我们只要使用Lombok的@Builder注解, 即可支持Builder构建对象。
更多的Lombok知识,可以参考之前的文章《Lombok,简化代码的神器,你值得拥有》
import java.util.List;
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Builder
public class Book {
private String name;
private String isbn;
private List<String> authors;
}
Book book = Book.builder().name("Hello java")
.isbn("1234567890").authors(Arrays.asList("Eric"))
.build();
// Book [name=Hello java, isbn=1234567890, authors=[Eric]]
System.out.println(book);
03
▼
写通用的Builder<T>(JDK1.8以上)
import java.util.List;
public class Book {
private String name;
private String isbn;
private List<String> authors;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getIsbn() {
return isbn;
}
public void setIsbn(String isbn) {
this.isbn = isbn;
}
public List<String> getAuthors() {
return authors;
}
public void setAuthors(List<String> authors) {
this.authors = authors;
}
@Override
public String toString() {
return "Book [name=" + name + ", isbn=" + isbn + ", authors=" + authors + "]";
}
}
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Supplier;
/**
* 通用的 Builder 模式构建器
*
* @author: CipherCui
* @since 2019/8/29
*/
public class Builder<T> {
private final Supplier<T> instantiator;
private List<Consumer<T>> modifiers = new ArrayList<>();
public 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 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);
}
}
Book book = Builder.of(Book::new)
.with(Book::setName, "Hello Java")
.with(Book::setIsbn, "1234567890")
.with(Book::setAuthors, Arrays.asList("Eric"))
.build();
System.out.println(book);
上述三种方式,你会采用哪一种呢?在可以使用Lombok的项目中,我更倾向于使用Lombok来完成,你的选择呢?