乐趣区

手撸lombok

拥抱 lombok, 它会帮助我们解决一些让我们很烦躁的问题

去掉 Setter 和 Getter
@Setter @Getter public class UserDTO {
@NotNull
private String username;
@NotNull
private int age;

public User convertToUser(){
UserDTOConvert userDTOConvert = new UserDTOConvert();
User convert = userDTOConvert.convert(this);
return convert;
}

public UserDTO convertFor(User user){
UserDTOConvert userDTOConvert = new UserDTOConvert();
UserDTO convert = userDTOConvert.reverse().convert(user);
return convert;
}

private static class UserDTOConvert extends Converter<UserDTO, User> {
@Override
protected User doForward(UserDTO userDTO) {
User user = new User();
BeanUtils.copyProperties(userDTO,user);
return user;
}

@Override
protected UserDTO doBackward(User user) {
throw new AssertionError(“ 不支持逆向转化方法!”);
}
}
}
看到了吧,烦人的 Getter 和 Setter 方法已经去掉了。
bean 中的链式风格
改造前
public class Student {
private String name;
private int age;

public String getName() {
return name;
}

public Student setName(String name) {
this.name = name;
return this;
}

public int getAge() {
return age;
}

public Student setAge(int age) {
return this;
}
}
相信合理使用这样的链式代码,会更多的程序带来很好的可读性,那看一下如果使用 lombok 进行改善呢,请使用 @Accessors(chain = true),看如下代码:
@Accessors(chain = true)
@Setter
@Getter
public class Student {
private String name;
private int age;
}
这样就完成了一个对于 bean 来讲很友好的链式操作。
静态构造方法
静态构造方法的语义和简化程度真的高于直接去 new 一个对象。比如 new 一个 List 对象,过去的使用是这样的:
List<String> list = new ArrayList<>();
看一下 guava 中的创建方式:
List<String> list = Lists.newArrayList();
Lists 命名是一种约定(俗话说:约定优于配置),它是指 Lists 是 List 这个类的一个工具类,那么使用 List 的工具类去产生 List,这样的语义是不是要比直接 new 一个子类来的更直接一些呢,答案是肯定的,再比如如果有一个工具类叫做 Maps,那你是否想到了创建 Map 的方法呢:
HashMap<String, String> objectObjectHashMap = Maps.newHashMap();
接上上边的静态构造方法和必传参数的构造方法,使用 lombok 将更改成如下写法(@RequiredArgsConstructor 和 @NonNull):
@Accessors(chain = true)
@Setter
@Getter
@RequiredArgsConstructor(staticName = “ofName”)
public class Student {
@NonNull private String name;
private int age;
}
测试代码:
Student student = Student.ofName(“zs”);
这样构建出的 bean 语义是否要比直接 new 一个含参的构造方法 (包含 name 的构造方法) 要好很多。
当然,看过很多源码以后,我想相信将静态构造方法 ofName 换成 of 会先的更加简洁:
@Accessors(chain = true)
@Setter
@Getter
@RequiredArgsConstructor(staticName = “of”)
public class Student {
@NonNull private String name;
private int age;
}
测试代码:
Student student = Student.of(“zs”);
当然他仍然是支持链式调用的:
Student student = Student.of(“zs”).setAge(24);
这样来写代码,真的很简洁,并且可读性很强。
使用 builder
@Builder
public class Student {
private String name;
private int age;
}

调用方式:
Student student = Student.builder().name(“zs”).age(24).build();

代理模式
正如我们所知的,在程序中调用 rest 接口是一个常见的行为动作,如果你和我一样使用过 spring 的 RestTemplate,我相信你会我和一样,对他抛出的非 http 状态码异常深恶痛绝。
所以我们考虑将 RestTemplate 最为底层包装器进行包装器模式的设计:
public abstract class FilterRestTemplate implements RestOperations {
protected volatile RestTemplate restTemplate;

protected FilterRestTemplate(RestTemplate restTemplate){
this.restTemplate = restTemplate;
}

// 实现 RestOperations 所有的接口
}

然后再由扩展类对 FilterRestTemplate 进行包装扩展:
public class ExtractRestTemplate extends FilterRestTemplate {
private RestTemplate restTemplate;
public ExtractRestTemplate(RestTemplate restTemplate) {
super(restTemplate);
this.restTemplate = restTemplate;
}

public <T> RestResponseDTO<T> postForEntityWithNoException(String url, Object request, Class<T> responseType, Object… uriVariables)
throws RestClientException {
RestResponseDTO<T> restResponseDTO = new RestResponseDTO<T>();
ResponseEntity<T> tResponseEntity;
try {
tResponseEntity = restTemplate.postForEntity(url, request, responseType, uriVariables);
restResponseDTO.setData(tResponseEntity.getBody());
restResponseDTO.setMessage(tResponseEntity.getStatusCode().name());
restResponseDTO.setStatusCode(tResponseEntity.getStatusCodeValue());
}catch (Exception e){
restResponseDTO.setStatusCode(RestResponseDTO.UNKNOWN_ERROR);
restResponseDTO.setMessage(e.getMessage());
restResponseDTO.setData(null);
}
return restResponseDTO;
}
}

包装器 ExtractRestTemplate 很完美的更改了异常抛出的行为,让程序更具有容错性。在这里我们不考虑 ExtractRestTemplate 完成的功能,让我们把焦点放在 FilterRestTemplate 上,“实现 RestOperations 所有的接口”, 这个操作绝对不是一时半会可以写完的,当时在重构之前我几乎写了半个小时, 如下:
public abstract class FilterRestTemplate implements RestOperations {

protected volatile RestTemplate restTemplate;

protected FilterRestTemplate(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}

@Override
public <T> T getForObject(String url, Class<T> responseType, Object… uriVariables) throws RestClientException {
return restTemplate.getForObject(url,responseType,uriVariables);
}

@Override
public <T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException {
return restTemplate.getForObject(url,responseType,uriVariables);
}

@Override
public <T> T getForObject(URI url, Class<T> responseType) throws RestClientException {
return restTemplate.getForObject(url,responseType);
}

@Override
public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object… uriVariables) throws RestClientException {
return restTemplate.getForEntity(url,responseType,uriVariables);
}
// 其他实现代码略。。。
}

我相信你看了以上代码,你会和我一样觉得恶心反胃,后来我用 lombok 提供的代理注解优化了我的代码(@Delegate):
@AllArgsConstructor
public abstract class FilterRestTemplate implements RestOperations {
@Delegate
protected volatile RestTemplate restTemplate;
}

这几行代码完全替代上述那些冗长的代码。
是不是很简洁,做一个拥抱 lombok 的程序员吧。

退出移动版