1. 引言
在本周五,集中代码 CR 的时候
小王写的一段代码引起了领导的质问
public class InsuranceOrderDTO {
// 保单号
private String policyNo;
// 关联人信息
private InsRelationshipDTO insRelationShipDTO;
// 保单 url
private String policyUrl;
// 发票信息
private InvoiceDTO invoiceDTO;
}
领导:“我看你这个初始化的方法,是嵌入在各个流程中,但是有的地方只用了保单的 url,有些地方只用了发票信息,你这统一初始化了上下文,不是浪费资源么,能少一次外调就少一次外调”
小王:“领导,我不这样写,需要的时候才去查,这个查询的代码会整的到处都是,不优雅啊,我这边初始化后,上下文中直接用,多完美啊”
领导:“你这不行啊,耗费了无用的 rt”
小王:“领导,这点 rt 算不了什么啊”
在小王和领导 battle 的时候,我就知道,这个时候,我装x 的时候到了
我:“领导,我觉得可以实用惰性加载来解决一下这个问题”
小王白了我一眼,“又整什么花活”
领导:“小杨,你展开说说”
2. 惰性加载
我:“何谓惰性加载,即在我们切实需要某份数据的时候,再去执行查询或计算动作,加载数据。而不是预先直接执行某个查询或者计算动作,然后将数据放在上下文。
快过年了,举个例子,你是现在直接去银行取钱包个红包放在身上方便,还是说等真正要去包红包,再去银行取钱方便呢?答案当然是,不包红包的方便了”
当这个梗没有响的时候,我发现会议室的气氛有点尴尬了,清了清嗓子
“其实 Java 中已经有了 惰性计算的机制,我们可以这样写”
Supplier<String> policyUrlSupplier = () -> queryPolicyUrl(policyNo)
String policyUrl = policyUrlSupplier.get()
类比到我们的类中可以这样改造
public class InsuranceOrderDTO {
// 保单号
private String policyNo;
// 关联人信息
private InsRelationshipDTO;
// 保单 url
private String policyUrl;
// 发票信息
private InvoiceDTO invoiceDTO;
public String getPolicyUrl() {
policyUrl = () -> policyUrlService.queryPolicyUrl(policyNo).get();
}
.......
}
此时,小王有点不服气 “你这样写不行啊,我放在上下文,撑死了最多查一次,你这样每次都得去 get ,重新查询”
我有点无语了,我就是写个 demo,这小王的脑袋瓜咋转不过来
领导:“你这个思路可以,来拓展成一个工具类,可以在组内推广一下”
我:“不愧是领导你啊,还得是你有远见,我立马改一下”
2.1 通用实现
public class LazyBuilder<T> implements Supplier<T> {
private final Supplier<T> supplier;
private T value;
public LazyBuilder(Supplier<T> supplier) {
this.supplier = supplier;
}
public static <T> LazyBuilder<T> build(Supplier<T> supplier) {
return new LazyBuilder<>(supplier);
}
@Override
public T get() {
return orElse(null);
}
public T orElse(T defaultValue) {
// 缓存值不存在,重新查询
if (Objects.isNull(value)) {
value = Optional.ofNullable(supplier.get()).orElse(defaultValue);
}
return value;
}
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
// 缓存值不存在,重新查询
if (Objects.isNull(value)) {
value = Optional.ofNullable(supplier.get()).orElseThrow(exceptionSupplier);
}
return value;
}
}
领导:“小杨这代码写的可以,很优雅。小王,你多跟人家学学,你就照着小杨的这一段代码,把你的 InsuranceOrderDTO 修改一下,我看你有没有学习到精髓”
小王:“emmm,好的领导”
public class InsuranceOrderDTO {
// 保单号
private LazyBulider<String> policyNo;
// 关联人信息
private LazyBuilder<InsRelationshipDTO> insRelationshipDTO;
// 保单 url
private LazyBuilder<String> policyUrl;
// 发票信息
private LazyBuilder<InvoiceDTO> invoiceDTO;
...
}
InsuranceOrderDTO insOrderDTO = new InsuranceOrderDTO()
insOrderDTO.setPolicyNo(LazyBuilder.build(() -> policyService.queryPolicy(userId)))
小王:领导,不对有问题啊,我这个保单号也惰性加载了,然后我想去获得保单的 url 有需要惰性加载,我似乎要变成这样了
insOrderDTO.setPolicyUrl(LazyBulider.build() -> policyUrlService.queryUrl(insOrderDTO.getPolicyNo()))
小王:这样一弄,我的保单号立马去查询了,没有意义了啊
我:“这个好弄啊,你这样改一下就可以”
public <S> LazyBulider<S> map(Function<T, S> function) {
return LazyBulider.of(() -> function.apply(get()));
}
我:那么获取保单url 就是这样了
insOrderDTO.setPolicyUrl(insOrderDTO.getPolicyNo().map(polciNo -> LazyBulider.build() -> policyUrlService.queryUrl(policyNo)))
此时此刻,领导为我鼓起了掌。
我知道了,今天这个 b 被我装到了。挥一挥衣袖,“没有啦,是领导平时教导有方”
3. 完整 LazyBuilder 工具类
既然,你看到这里了,我建议你收藏一波,因为今天是我装 x,但是当你用了这个工具类,下一个装 x 的就是你了
我行,你也行
public class LazyBuilder<T> implements Supplier<T> {
private final Supplier<T> supplier;
private T value;
public LazyBuilder(Supplier<T> supplier) {
this.supplier = supplier;
}
public static <T> LazyBuilder<T> build(Supplier<T> supplier) {
return new LazyBuilder<>(supplier);
}
@Override
public T get() {
return orElse(null);
}
public T orElse(T defaultValue) {
// 缓存值不存在,重新查询
if (Objects.isNull(value)) {
value = Optional.ofNullable(supplier.get()).orElse(defaultValue)
}
return value;
}
public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
// 缓存值不存在,重新查询
if (Objects.isNull(value)) {
value = Optional.ofNullable(supplier.get()).orElseThrow(exceptionSupplier);
}
return value;
}
public <S> LazyBuilder<S> map(Function<T, S> function) {
return LazyBuilder.build(() -> function.apply(get()));
}
}
4. 闲言碎语
这周,去公司健身房,碰到一老外
身上肌肉练的和灭霸一样,我正举着铁的呢,通过镜子,我发现这老外一直盯着我的屁股看
我正在寻思委婉又不礼貌的用 English 交涉一下,让这老外礼貌一点,别看我屁股
结果老外过来用流利的中文说:同学你好,你的裤子上粘着我的手套
尬住了。。。