如何用函數式優雅的寫一個增刪改查

如何用函數式優雅的寫一個增刪改查

作爲一名專業的CRUD-Boy,本篇介紹如何使用io.vavr工具包來寫一個比較舒服的有則更新,無則新增CRUD小需求

一、io.vavr

1).Optional怎麼玩?jdk8

// 有則更新,無則新增,不推薦
if(optional.isPresent){
    // 有則更新
    optional.get();
} else {
    // 無則新增
}

或者


optional.map(record -> {
  // 有則更新
  update(record);
})
// 無則新增
.orElse(getNewRecord());

2).如果不用Optional如何寫?

// 把Java的Optional轉爲io.vavr的Option,然後判斷空和非空
Option.ofOptional(optional).onEmpty(() -> {
    // 處理空的情況,無則新增
    insert();
}).peek(record -> {
    // 處理非空的情況,有則更新
    update(record);
});

io.vavr介紹:
https://www.vavr.io/

用到的武器:Optional -> Option

// optional *value*, no more nulls
Option<T> option = Option.of(...);

引入pom

 <dependency>
     <groupId>io.vavr</groupId>
     <artifactId>vavr</artifactId>
     <version>0.10.3</version>
</dependency>

二、寫一個Repo

/**
 * @author luoyu.lzy
 * @Title: AppUserRepo.java
 * @Description:
 * @date 2021/9/1.
 */
public interface AppUserRepo {

    /**
     * 持久化,有則更新,無則新增
     * @param appUser
     * @return
     */
    AppUser save(AppUser appUser);

    /**
     * 根據id獲取DTO
     * @param id
     * @return
     */
    AppUser getById(Long id);
}

三、實現這個Repo


/**
 * @author luoyu.lzy
 * @Title:AppUserRepoImpl.java
 * @Description:用戶Repo實現類
 * @date 2021/9/1.
 */
@Component
public class AppUserRepoImpl implements AppUserRepo {
    
    @Autowired
    private AppUserDAO appUserDAO;
    
   /**
    * 查詢DB,根據id獲取Record
    */
    private Optional<AppUserDO> getRecordById(Long id) {
       return Optional.ofNullable(appUserDAO.selectByPrimaryKey(id));
    }
    
    /**
    * bean轉換 DO -> DTO
    */
     @Override
    public AppUser getById(Long id) {
        Optional<AppUserDO> optional = getRecordById(id);
        // toAppUser bean轉換
        return optional.map(this::toAppUser).orElse(null);
    }
    
   /**
    * 保存,有則更新部分字段,無則新增
    */
    @Override
    public AppUser save(AppUser appUser) {
        Option.ofOptional(getRecordById(appUser.getId())).onEmpty(() -> {
            AppUserDO record = toAppUserDO(appUser);
            record.setGmtCreate(Calendar.getInstance().getTime());
            record.setGmtModified(Calendar.getInstance().getTime());
            int insertResult = appUserDAO.insert(record);
            if (insertResult > 0) {
                record.setId(record.getId());
            }
        }).peek(record -> {
            record.setStatus(appUser.getStatus());
            appUserDAO.updateByPrimaryKey(record);
        });
        return appUser;
    }

}

四、Option.of 源碼分析

我們回到這段代碼, 分別是Option.of(Optional).onEmpty().peek() 這3個api,我們來看看核心代碼。

// 把Java的Optional轉爲io.vavr的Option
Option.ofOptional(xxxOptinal).onEmpty(() -> {
    // 處理空的情況
}).peek(record -> {
    // 處理非空的情況
});

再來看看Option.ofOptional源碼


    /**
     * 包裹Optional對象,返回Option對象     
     */
    @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
    static <T> Option<T> ofOptional(Optional<? extends T> optional) {
    // optional不能爲null
        Objects.requireNonNull(optional, "optional is null");
        //通過java.util.Optional.map(Option.of)方法來包裝optional每個元素
        return optional.<Option<T>>map(Option::of).orElseGet(Option::none);
    }
       
     static <T> Option<T> of(T value) {
        // none和same分別用來生產None對象和Same對象,None和Same代表無元素(None=無元素)和有元素(Same=相同類型的元素)
        return (value == null) ? none() : some(value);
    }
    
    /**
     * java.util.Optional
     * 通過Optional.map方法,返回Optional對象
    */
    public<U> Optional<U> map(Function<? super T, ? extends U> mapper) {
        Objects.requireNonNull(mapper);
        if (!isPresent())
            return empty();
        else {
            // 執行mapper函數
            return Optional.ofNullable(mapper.apply(value));
        }
    }
    
   /**
    * 處理OnEmpty事件,如果元素爲空,則執行 Runnable.run
    */
    default Option<T> onEmpty(Runnable action) {
        Objects.requireNonNull(action, "action is null");
        if (isEmpty()) {
            action.run();
        }
        return this;
    }
    
   /**
    * 處理peek事件,如果不爲empty,則執行Consumer.accept
    */
    default Option<T> peek(Consumer<? super T> action) {
        Objects.requireNonNull(action, "action is null");
        if (isDefined()) {
            action.accept(get());
        }
        return this;
    }
    
    

五、整完,CRUD更簡潔

六、Optional的進化

Java 9 Optional API 新增方法 or,可以實現類似Option.onEmpty的功能

Optional<T> optional = Optional.empty();
Optional<T> result = optional.or(() -> doSomeThionEmpty);

落雨 http://js-dev.cn
2021-09-13 21:13:00

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