lombok——java開發必備

擁抱lombok

上邊的DTO代碼,已經讓我看的很累了,我相信讀者也是一樣,看到那麼多的Getter和Setter方法,太煩躁了,那時候有什麼方法可以簡化這些呢。
請擁抱lombok,它會幫助我們解決一些讓我們很煩躁的問題

去掉Setter和Getter

其實這個標題,我不太想說,因爲網上太多,但是因爲很多人告訴我,他們根本就不知道lombok的存在,所以爲了讓讀者更好的學習,我願意寫這樣一個例子:

@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方法已經去掉了。
但是上邊的例子根本不足以體現lombok的強大。我希望寫一些網上很難查到,或者很少人進行說明的lombok的使用以及在使用時程序語義上的說明。
比如:@Data,@AllArgsConstructor,@NoArgsConstructor..這些我就不進行一一說明了,請大家自行查詢資料.

bean中的鏈式風格

什麼是鏈式風格?我來舉個例子,看下面這個Student的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;
    }
}

仔細看一下set方法,這樣的設置便是chain的style,調用的時候,可以這樣使用:

Student student = new Student()
        .setAge(24)
        .setName("zs");

相信合理使用這樣的鏈式代碼,會更多的程序帶來很好的可讀性,那看一下如果使用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();

好了,如果你理解了我說的語義,那麼,你已經向成爲java程序員更近了一步了。

再回過頭來看剛剛的Student,很多時候,我們去寫Student這個bean的時候,他會有一些必輸字段,比如Student中的name字段,一般處理的方式是將name字段包裝成一個構造方法,只有傳入name這樣的構造方法,才能創建一個Student對象。

接上上邊的靜態構造方法和必傳參數的構造方法,使用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模式我不想再多解釋了,讀者可以看一下《Head First》(設計模式) 的建造者模式。

今天其實要說的是一種變種的builder模式,那就是構建bean的builder模式,其實主要的思想是帶着大家一起看一下lombok給我們帶來了什麼。

看一下Student這個類的原始builder狀態:

public class Student {
    private String name;
    private int age;

    public String getName() {
            return name;
    }

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

    public int getAge() {
            return age;
    }

    public void setAge(int age) {
            this.age = age;
    }

    public static Builder builder(){
            return new Builder();
    }
    public static class Builder{
            private String name;
            private int age;
            public Builder name(String name){
                    this.name = name;
                    return this;
            }

            public Builder age(int age){
                    this.age = age;
                    return this;
            }

            public Student build(){
                    Student student = new Student();
                    student.setAge(age);
                    student.setName(name);
                    return student;
            }
    }

}

調用方式:

Student student = Student.builder().name("zs").age(24).build();

這樣的builder代碼,讓我是在噁心難受,於是我打算用lombok重構這段代碼:

@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的程序員吧。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章