簡體   English   中英

避免復雜分支的最佳方法-Java

[英]Best way to avoid complicated if else branching - Java

我有rest API,它使用幾個參數(作為requestparams)來搜索實體。 此搜索可能有多種變體。 下列方法最終會調用以給定參數搜索實體。

public List<Person> searchPerson(final String name, 
           final String city, final String state, final String code) {
    if( name != null && city != null && state != null && code != null ){
        //Search person in database with above all parameters
        //personRepositoy is spring data repository. 
        personRepositoy.findByNameAndCityAndStateAndCode(name, city, state, code);
    } else if( city != null && state != null && code != null){
        personRepositoy.findByCityAndStateAndCode(name, city, state, code)
    }
}

有沒有辦法可以避免在這里出現復雜的分支(容易出錯,不那么容易重構)? 可能使用集合或函數式編程概念嗎? 我真的不願意編寫這種分支代碼(因為這些代碼很難維護)

您可以為以下內容創建自己的實用程序:

public static boolean requireNonNull(Object... objects) {
    for(Object obj : objects) {
        if(obj == null) return false;
    }
    return true;
}

用法示例

public List<Person> searchPerson(final String name, final String city, 
                                 final String state, final String code) {
    if(MyUtilityClass.requireNonNull(name, city, state, code)) {
        //Search person in database with above all parameters
        //personRepositoy is spring data repository. 
        personRepositoy.findByNameAndCityAndStateAndCode(name, city, state, code);
    } else if(MyUtilityClass.requireNonNull(city, state, code)) {
        personRepositoy.findByCityAndStateAndCode(city, state, code)
    }
}

city != null && state != null && code != null可能保存在變量中。

boolean cityStateCodeGiven = city != null && state != null && code != null;

if(name != null && cityStateCodeGiven) {
    // name, city, state, code are given
} else if (cityStateCodeGiven) {
    // city, state, code are given
}

您無需兩次或多次重新檢查某些條件。

例如, cityStateCodeGiven可能會拆分為cityStateGiven + codeGiven name != null && cityStateCodeGiven可以分組為nameCityStateCodeGiven

變量的名稱將告訴變量檢查哪些條件。


此外,您可以將這些聲明放在方法的開頭。 它將為您稍后在代碼中使用的方法提供一些提示。

boolean cityStateCodeGiven = city != null && state != null && code != null;
boolean nameCityStateCodeGiven = cityStateCodeGiven && name != null;

為清楚起見,代碼如下

if(name!=null)
{
  if(city!=null)
  {
    if(state!=null
    {
      if(code!=null)
      { 
        // do search using all
        }
        //search using name , city , code
        }
         // search using name , city
         } 
         //search using name only
         }

在不知道不同支票如何相互作用的情況下,很難說出來。

無論如何,下面的文章為您提供5種不同的解決方案(模式),以使if-else條件更易讀: Anti-If:缺少的模式

希望您可以在代碼中使用其中之一。

我提議更廣泛地研究這個問題。 我可以期待以下事情:

  1. 您已經有4個不同的搜索屬性可搜索人物;
  2. 我希望您將來會有更多的搜索字段以及更多不同的組合。

因此,我提供將所有這些字段組合到特殊對象SearchPersonRequest

然后,您有了這個對象,它可能會有特殊的行為, 例如為搜索引擎創建搜索請求,即SpringData 當您有多個文件要使用多個組合進行搜索時,使用JpaSpecificationExecutor會非常靈活。

這是我的重點。 舉例來說,我為您提供了這方面的第一種方法(您會看到Lombok批注,它只是為了簡化代碼;不需要使用它):

SearchPersonRequest

@Builder
public class SearchPersonRequest {

    private String name;
    private String city;
    private String state;
    private String code;

    public Specification<Person> createSpecification() {
        List<Specification<Person>> specifications = getSpecifications();
        Specifications<Person> spec = null;

        if (!specifications.isEmpty()) {
            Iterator<Specification<Person>> it = specifications.iterator();
            spec = where(it.next());

            while (it.hasNext()) {
                spec = spec.and(it.next());
            }
        }

        return spec;
    }

    private List<Specification<Person>> getSpecifications() {
        return Arrays.stream(Field.values())
                     .filter(field -> field.isExists(this))
                     .map(field -> (Specification<Person>)(root, query, builder) -> builder.equal(root.get(field.id), field.get.apply(this)))
                     .collect(Collectors.toList());
    }

    @RequiredArgsConstructor(access = AccessLevel.PACKAGE)
    private enum Field {
        NAME("name", request -> request.name),
        CITY("city", request -> request.city),
        STATE("state", request -> request.state),
        CODE("code", request -> request.code);

        private final String id;
        private final Function<SearchPersonRequest, String> get;

        private boolean isExists(SearchPersonRequest request) {
            return StringUtils.isNotBlank(get.apply(request));
        }
    }

}

人控者

@RestController
@RequiredArgsConstructor
public class PersonController {

    private final PersonService personService;

    public List<Person> searchPerson(@RequestParam String name,
                                     @RequestParam String city,
                                     @RequestParam String state,
                                     @RequestParam String code) {
        SearchPersonRequest searchPersonRequest = SearchPersonRequest.builder()
                                                                     .name(name)
                                                                     .city(city)
                                                                     .state(state)
                                                                     .code(code)
                                                                     .build();
        return searchPerson(searchPersonRequest);
    }

    public List<Person> searchPerson(@RequestBody SearchPersonRequest searchPersonRequest) {
        return personService.searchPerson(searchPersonRequest);
    }

}

人員服務

@Service
@RequiredArgsConstructor
public class PersonService {

    private final PersonRepository personRepository;

    public List<Person> searchPerson(SearchPersonRequest searchPersonRequest) {
        Specification<Person> spec = searchPersonRequest.createSpecification();
        return spec != null ? personRepository.findAll(spec) : Collections.emptyList();
    }
}

人員資料庫

public interface PersonRepository extends JpaSpecificationExecutor<Person> {

}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM