V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
nicepink
V2EX  ›  程序员

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

  •  4
     
  •   nicepink · Oct 21, 2021 · 4195 views
    This topic created in 1661 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
    itning
        1
    itning  
       Oct 21, 2021
    封装 继承 多态
    aguesuka
        2
    aguesuka  
       Oct 21, 2021
    把耗时函数改成 lambda 保存到 List 中
    zoharSoul
        3
    zoharSoul  
       Oct 21, 2021
    没什么问题 挺好看懂的
    zsl199512101234
        4
    zsl199512101234  
       Oct 21, 2021   ❤️ 1
    二楼的方法,把耗时函数改成 lambda 保存到 list 中去,然后循环调用直到不为空就赋值并且 break
    zjsxwc
        5
    zjsxwc  
       Oct 21, 2021
    for 循环遍历 List
    chendy
        6
    chendy  
       Oct 21, 2021
    第一步,把“取 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
        7
    admol  
       Oct 21, 2021
    如果你只是觉得 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
        8
    zsl199512101234  
       Oct 21, 2021
    ```java
    @FunctionalInterface
    public interface OfficeCodeService {
    BookingOfficeCode getOfficeCode(BrGeneralInfoDto brGeneralInfoDto);
    }
    ```
    mango88
        9
    mango88  
       Oct 21, 2021
    耗时操作有优先级要求吗 ?

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

    理解错了,6L 的方案会好点。
    ipwx
        12
    ipwx  
       Oct 21, 2021
    不懂 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
        13
    wolfie  
       Oct 21, 2021
    在 Optional 基础上,定义一个 OptionalWrapper 。

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

    可以链式调用。
    Guiyanakuang
        14
    Guiyanakuang  
       Oct 21, 2021
    为了保证可读性不建议抽取保存到 list 里,只需要将重复部分独立为单个函数,每个函数返回 this,链式调用逻辑更清晰
    wolfie
        15
    wolfie  
       Oct 21, 2021   ❤️ 3
    ```
    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
        16
    hingbong  
       Oct 21, 2021
    ```
    public OptionalChain<T> or(Predicate<T> predicate, Supplier<T> supplier) {
    if (predicate.test()) {
    return this;
    }
    value = supplier.get();
    }
    ```
    判断条件也动态起来?
    fkdog
        17
    fkdog  
       Oct 21, 2021
    将所有的 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
        18
    NeroKamin  
       Oct 21, 2021
    @wolfie 第一直觉也是把 function 放到 list 遍历,再看这个链式调用,明显感觉要好很多
    yazinnnn
        19
    yazinnnn  
       Oct 21, 2021
    functions.stream()
    .parallel()
    .map(it -> it.apply(""))
    .filter(StringUtils::isNotBlank)
    .findFirst()
    .orElse("");

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