• 请不要在回答技术问题时复制粘贴 AI 生成的内容
nicepink
V2EX  ›  程序员

[ Java ] 方法里有很多判断需要提前结束,很多重复代码,求大神!

  •  4
     
  •   nicepink · Oct 21, 2021 · 4668 views
    This topic created in 1840 days ago, the information mentioned may be changed or developed.

    因为几个查询条件耗时久查到结果就提前结束,但是有重复的地方觉得不够优雅 if 判断那一块

        private void prepareBookingOffice(BrChangedEvent brChangedEvent) {
            BrGeneralInfoDto brGeneralInfoDto = Optional.ofNullable(brChangedEvent)
                    .map(BrChangedEvent::getBrDto)
                    .map(BrDto::getGeneralInfo)
                    .orElse(BrGeneralInfoDto.builder().build());
    
            if (StringUtils.isNotEmpty(brGeneralInfoDto.getBookingOfficeCode())) {
                return;
            }
    
            // 耗时
            String officeCode = getOfficeCodeByOfficeUnlLocCode(brGeneralInfoDto);
            // 重复
            if (StringUtils.isNotEmpty(officeCode)) {
                brGeneralInfoDto.setBookingOfficeCode(officeCode);
                return;
            }
    
            // 耗时
            officeCode = getOfficeCodeByPor(brChangedEvent);
            // 重复
            if (StringUtils.isNotEmpty(officeCode)) {
                brGeneralInfoDto.setBookingOfficeCode(officeCode);
                return;
            }
    
            // 耗时
            officeCode = getOfficeCodeByFnd(brChangedEvent);
            // 重复
            if (StringUtils.isNotEmpty(officeCode)) {
                brGeneralInfoDto.setBookingOfficeCode(officeCode);
                return;
            }
    
            // 耗时
            officeCode = getOfficeCodeByPol(brChangedEvent);
            // 重复
            if (StringUtils.isNotEmpty(officeCode)) {
                brGeneralInfoDto.setBookingOfficeCode(officeCode);
            }
        }
    
    Supplement 1  ·  Oct 21, 2021

    有些回复有些不太理解(知识储备不够...),后续再研究研究

    目前先尝试了这位老哥的写法:

    public class OptionalChain<T> {
    
        private T value;
    
        private OptionalChain(T val) {
            value = val;
        }
    
        public static <T> OptionalChain<T> of(Supplier<T> supplier) {
            return new OptionalChain<>(supplier.get());
        }
    
        public OptionalChain<T> or(Supplier<T> supplier) {
            if (StringUtils.isEmpty(value)) {
                value = supplier.get();
            }
            return this;
        }
    
        public T get() {
            return value;
        }
    
    }
    
    private void prepareBookingOffice(BrChangedEvent brChangedEvent) {
        BrGeneralInfoDto brGeneralInfoDto = Optional.ofNullable(brChangedEvent)
                .map(BrChangedEvent::getBrDto)
                .map(BrDto::getGeneralInfo)
                .orElse(BrGeneralInfoDto.builder().build());
    
        brGeneralInfoDto.setBookingOfficeCode(OptionalChain.of(() -> brGeneralInfoDto.getBookingOfficeCode())
                .or(() -> getOfficeCodeByOfficeUnlLocCode(brGeneralInfoDto))
                .or(() -> getOfficeCodeByPor(brChangedEvent))
                .or(() -> getOfficeCodeByFnd(brChangedEvent))
                .or(() -> getOfficeCodeByPol(brChangedEvent))
                .or(() -> StringUtils.EMPTY)
                .get());
    
    }
    
    

    补充一下:

    • 这个问题起因是因为昨天 code review 的时候同事觉得我这里可以改进,但是没有思路
    • 这里耗时的地方其实也就是 call 其他服务去拿数据,顺序要固定,是业务上的要求
    • 有些老哥说觉得没必要改,其实我也在想有没有必要,主要是想让代码既清楚又不冗余
    23 replies  •  2021-10-21 23:04:15 +08:00
    stimulate1797
    stimulate1797
    Oct 21, 2021
    1
    封装 继承 多态
    aguesuka
    aguesuka
    Oct 21, 2021
    2
    把耗时函数改成 lambda 保存到 List 中
    zoharSoul
    zoharSoul
    Oct 21, 2021
    3
    没什么问题 挺好看懂的
    zsl199512101234
    zsl199512101234
    Oct 21, 2021❤️1
    4
    二楼的方法,把耗时函数改成 lambda 保存到 list 中去,然后循环调用直到不为空就赋值并且 break
    zjsxwc
    zjsxwc
    Oct 21, 2021
    5
    for 循环遍历 List
    chendy
    chendy
    Oct 21, 2021
    6
    第一步,把“取 officeCode”抽出去,如果方法不是很多而且也不怎么调整,做到这里就可以了

    private String getOfficeCode(BrChangedEvent e){
    String code = findOfficeCodeByA(e);
    if (!StringUtil.isEmpty(code)) {
    return code;
    }
    // 后面的差不多
    }

    如果方法比较多且需要调整,那么就进一步抽

    private List<Function<BrChangedEvent, String>> codeFinders;

    {
    codeFinders.add(this::findOfficeCodeByA);
    codeFinders.add(this::findOfficeCodeByB);
    codeFinders.add(this::findOfficeCodeByC);
    }


    private String getOfficeCode(BrChangedEvent e) {
    for(Function<BrChangedEvent, String>> finder : codeFinders) {
    String code = finder.apply(codeFinders);
    if(!StringUtil.isEmpty(code)){
    return code;
    }
    return null;
    }
    }
    admol
    admol
    Oct 21, 2021
    7
    如果你只是觉得 if 有点多,给你提供一个思路,你看是否可行

    public static void main(String[] args){
    String officeCode = null;
    if(Objects.nonNull(officeCode = a()) || Objects.nonNull(officeCode = b())|| Objects.nonNull(officeCode = c())){
    }else{
    officeCode = "default value";
    }
    System.out.println("officeCode:"+officeCode);
    }

    private static String c(){
    System.out.println("C");
    return "C";
    }
    private static String b(){
    System.out.println("B");
    return "B";
    }

    private static String a(){
    System.out.println("A");
    return null;
    }
    zsl199512101234
    zsl199512101234
    Oct 21, 2021
    8
    ```java
    @FunctionalInterface
    public interface OfficeCodeService {
    BookingOfficeCode getOfficeCode(BrGeneralInfoDto brGeneralInfoDto);
    }
    ```
    mango88
    mango88
    Oct 21, 2021
    9
    耗时操作有优先级要求吗 ?

    还是只要任一返回值就可以了 ? 如果是任一个操作返回就满足需求,可以试试用 CompletableFuture.anyOf()
    uCharles
    uCharles
    Oct 21, 2021
    10
    试试抽取之后用 Optional 来进行判断
    mango88
    mango88
    Oct 21, 2021
    11
    @mango88 每一步耗时操作可能会有空值返回 这样就不行了。

    理解错了,6L 的方案会好点。
    ipwx
    ipwx
    Oct 21, 2021
    12
    不懂 Java,伪代码

    interface IAction { String run(); }

    class GetOfficeCodeByOfficeUnlLocCodeAction implements IAction { ... };
    class GetOfficeCodeByPorAction implements IAction { ... };

    。。。


    List<IAction> actions = {
    new GetOfficeCodeByOfficeUnlLocCodeAction(...),
    new GetOfficeCodeByPorAction(...)
    };

    for (action in actions) {
    String officeCode = getOfficeCodeByOfficeUnlLocCode(brGeneralInfoDto);
    // 重复
    if (StringUtils.isNotEmpty(officeCode)) {
    brGeneralInfoDto.setBookingOfficeCode(officeCode);
    return;
    }
    }
    wolfie
    wolfie
    Oct 21, 2021
    13
    在 Optional 基础上,定义一个 OptionalWrapper 。

    OptionalWrapper<T> or(Supplier<T> supplier)

    可以链式调用。
    Guiyanakuang
    Guiyanakuang
    Oct 21, 2021
    14
    为了保证可读性不建议抽取保存到 list 里,只需要将重复部分独立为单个函数,每个函数返回 this,链式调用逻辑更清晰
    wolfie
    wolfie
    Oct 21, 2021❤️3
    15
    ```
    class OptionalChain<T> {

    private T value;

    private OptionalChain(T val) {
    value = val;
    }

    public static <T> OptionalChain<T> of(Supplier<T> supplier) {
    return new OptionalChain<>(supplier.get());
    }

    public OptionalChain<T> or(Supplier<T> supplier) {
    if (value == null) {
    value = supplier.get();
    }
    return this;
    }

    public T get() {
    return value;
    }

    }
    ```
    hingbong
    hingbong
    Oct 21, 2021
    16
    ```
    public OptionalChain<T> or(Predicate<T> predicate, Supplier<T> supplier) {
    if (predicate.test()) {
    return this;
    }
    value = supplier.get();
    }
    ```
    判断条件也动态起来?
    fkdog
    fkdog
    Oct 21, 2021
    17
    将所有的 getOfficeCodeByXXX()包装成 Function,然后塞进一个 List 。
    做 list 的迭代,执行 function.apply(),如果返回值非空,则 break 跳出迭代。

    ``` java
    List<Function<BrChangedEvent,String>> funcs= Arrays.asList(
    XXX::getOfficeCodeByOfficeUnlLocCode,
    XXX::getOfficeCodeByPor,
    XXX::getOfficeCodeByFnd,
    XXX::getOfficeCodeByPol);
    for(Function<BrChangedEvent,String> func:funcs){
    String officeCode = func.apply(brGeneralInfoDto);
    if(String.isNotEmpty(officeCode)){
    brGeneralInfoDto.setBookingOfficeCode(officeCode);
    }
    }
    ```
    NeroKamin
    NeroKamin
    Oct 21, 2021
    18
    @wolfie 第一直觉也是把 function 放到 list 遍历,再看这个链式调用,明显感觉要好很多
    yazinnnn
    yazinnnn
    Oct 21, 2021
    19
    functions.stream()
    .parallel()
    .map(it -> it.apply(""))
    .filter(StringUtils::isNotBlank)
    .findFirst()
    .orElse("");

    这样?
    itechify
    itechify
    Oct 21, 2021 via Android
    20
    remark,这样优化也有意义也有意思,后面再添加就不断的 append 进去
    crclz
    crclz
    Oct 21, 2021
    21
    初始实现没啥问题,第二版过拟合了(现在最简,但是不能很好应对新需求)
    bxb100
    bxb100
    Oct 21, 2021
    22
    可以考虑使用责任链设计模式
    jorneyr
    jorneyr
    Oct 21, 2021
    23
    if 已经是最优解了,其他各种花哨的办法难看的要死。
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   2740 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 55ms · UTC 00:25 · PVG 08:25 · LAX 16:25 · JFK 19:25
    ♥ Do have faith in what you're doing.