簡體   English   中英

Java 語義 - 有沒有辦法寫得更好?

[英]Java semantics - Is there a way to write this better?

我正在構建一個 Spring 后端。 我有一個控制器,它獲取一個“搜索對象”——一個包含 10 個字段的對象,只應填充其中一個字段,因此編寫了搜索函數(我沒有編寫但需要對其進行更改和重構)像這樣:

if( param1 != null ) user = getUserByParam1(param1);
else if ( param2 != null ) user = getUserByParam2(param2);
.
.
.
else if(lastName != null || lastName != null) user = getUserByName(firstName, lastName);
else user = getUserById(id);

if(user == null) throw costumException;
return user;

請注意最后的 2 個特殊情況 - 其中一個檢查 2 個參數的可用性而不是一個參數,並將它們發送到同一個函數(可以處理一個字段中的 null,但不能同時處理兩個字段),以及默認情況正在傳遞一個 ID(如果它不是 - 它在拋出異常之后由if (user == null)檢查處理)。

有沒有辦法重構這段代碼以使其更具可讀性/好看? 我可以使用任何設計模式或已知方法來做到這一點嗎? 或者它實際上是編寫這種功能的最佳方式?

我想了很多,但找不到更好的方法。 我有一個想法,以某種方式將填充的字段名稱及其值發送到另一個函數,該函數將在字段名稱上“切換大小寫”並將值發送到適當的函數,但它並沒有真正節省多少代碼(因為我仍然需要手動迭代所有字段以找到已填充的字段)而且我不確定它是否更具可讀性。

我對 Java 也很陌生,所以我不知道所有可用的 API 和接口,也許您可​​以向我尋求幫助。

注意:這只是您非常可怕的方法的一種解決方法。 正如評論中提到的,您的端點試圖做太多事情。 創建許多不同的端點會更好,這些端點都只需要所需的參數。 比只看 10 多個 if-else 語句更容易理解


您可以創建一個包含所有可能參數的數據class

public class UserRequest {
    private String lastName;
    private String firstName;

    // more fields, constructors, getters, setters etc.
}

然后有一個看起來像這樣的interface

public interface UserRequestResolver {
    User resolve(UserRequest request);
}

然后可以實現此接口以依賴於給定的參數(如果存在)。 返回一個找到的User或者只是null

下一步是,創建一個List<UserRequestResolver> resolvers ,並添加不同的實現,在 Java8+ 中你可以使用 lambdas:

resolvers.add(r -> r.getParam1() != null ? getUserByParam1(r.getParam1()) : null);
resolvers.add(r -> {
    if(r.getFirstName() == null && r.getLastName()) return null;
    return getUserByName(r.getFirstName(), r.getLastName());
});
// etc.

然后在接收UserRequest您可以簡單地遍歷resolvers並獲取第一個不為null返回值:

for(UserRequestResolver resolver : resolvers) {
    User user = resolver.resolve(request);
    if(user != null) return user;
}
throw costumException;

如果你是Stream的粉絲,那么你可以用這個替換上面的 for 循環:

return resolvers.stream()
    .map(resolver -> resolver.resolve(request))
    .filter(Objects::nonNull)
    .findFirst()
    .orElseThrow(() -> costumException);

根據您用於訪問數據的內容,您可以使用getByExample查詢。 您有一個在此處使用 Spring 數據的示例。 有了這個,你只需要從 api 獲取用戶類(你必須從你的 api 接收和對象搜索查詢,這個對象必須有點像用戶對象,因為參數看起來很相似)。

然后你有你的大 if/else 你從 api 傳遞用戶搜索對象,並在存儲庫中執行getByExample

user = getByExample(userSearchObject)

但這一切都是假設您在 api 中只收到一個填充在您的對象中的字段。 這將是最簡潔的方法。

否則,我建議將所有參數包裝到 api 中的一個類中,如下所示:

public class UserSearchQuery() {
    private String param1;
    private String param2;
    ...
    
    // getters + setters
}

然后使用標准查詢和標准查詢構建器(這里有一篇關於它的文章)。

在您的服務中,您只需執行以下操作:

public class UserService() {

private UserRepository repository;
   public User search(UserSearchQuery query) {
      return repository.search(query);
   }
}

並在回購中:

public class UserRepository() {
   private EntityManager em;
   
   public User search(UserSearchQuery query) {
      CriteriaBuilder builder = em.getCriteriaBuilder();
      CriteriaQuery<User> query = builder.createQuery(User.class);

      Root<User> user = query.from(User.class);
      List<Predicate> predicates = new ArrayList<>();
     
      if (query.getParam1() != null) {
          predicates.add(builder.equal(user.get("param1"), query.getParam1()));
      }
      ...
      // and the other ones goes here
   }
}

這樣做,您的 User 將只有 1 個搜索方法,而不再有 10 個方法,每個參數一個,並且要添加搜索條件,您只需向 UserSearchQuery 類添加一個新參數並添加一個新謂詞。 此外,如果有一天您希望能夠使用多個參數作為搜索條件,這已經完成了。

您可以發送請求參數中的所有字段,然后使用命令設計模式或策略設計模式針對不同情況實現不同的實現。

命令模式示例如下:

https://sourcemaking.com/design_patterns/command

策略設計模式: https : //sourcemaking.com/design_patterns/strategy

暫無
暫無

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

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