【问题标题】:Switch statement results in duplicated codeswitch 语句导致重复代码
【发布时间】:2022-06-11 00:39:11
【问题描述】:

我是一名初级开发人员,希望更好地组织我的代码。

现在,我正在处理表单编号。我检索表单编号的哈希映射,并且基于表单编号,我需要调用不同的方法。每个方法都接受相同的参数,但做的事情不同。

例如:


var formDetails = new inferForms.buildFormsMap

for(form in formDetails){

switch(form.formNumber){
          case "A1345":
            getExclusionDetails(account, state, form, businessDealing)
            break
          case "B254":
            getExclusionDetails(account, state, form, businessDealing)
            break
          case "B297":
            getPartnershipDetails(account, state, form, businessDealing)
            break
          case "C397":
            getBrokerageDetails(account, state, form, businessDealing)
            break
          case "D972":
            getBrokerageDetails(account, state, form, businessDealing)
            break
          case "E192":
            getBrokerageDetails(account, state, form, businessDealing)
            break
          case "E299":
            getBrokerageDetails(account, state, form, businessDealing)
            break
          case "F254":
            getLocationDetails(account, state, form, businessDealing)
            break
          case "F795":
            getLocationDetails(account, state, form, businessDealing)
            break
          case "G642":
            getContractDetails(period, wcmJurisdiction, newForm, wcmBusiness, frm)
            break
          case "G979":
            getContractDetails(period, wcmJurisdiction, newForm, wcmBusiness, frm)
            break
   }
}

一些注意事项:

-这些方法是由另一个开发人员构建的。他辞职了,所以我承担了他的工作,并希望进行重构以使其变得更好。

-起点是表格编号的HashMap。我生成 HashMap,然后循环遍历它以根据 HashMap 中的每个表单编号收集详细信息。

-即使我要将方法转换为对象继承结构,我仍然需要一个 switch 语句来知道要实例化哪个子类,不是吗? switch 语句会和上面的一样吗?

-其中一些 case 语句调用了完全相同的方法。有没有办法避免重复?

感谢您的所有帮助。我正在努力弄清楚如何更好地重新设计它。如果我可以提供更多详细信息,请告诉我。

【问题讨论】:

标签: java algorithm oop data-structures methods


【解决方案1】:

至少某些情况下具有相同的主体 -> 使用 switch 语句失败

switch(form.formNumber){
      case "A1345": // fall through
      case "B254":
        getExclusionDetails(account, state, form, businessDealing)
        break;
      case "B297":
        getPartnershipDetails(account, state, form, businessDealing)
        break
      case "C397": // fall through
      case "D972": // fall through
      case "E192": // fall through
      case "E299":
        getBrokerageDetails(account, state, form, businessDealing)
        break
      case "F254": // fall through
      case "F795":
        getLocationDetails(account, state, form, businessDealing)
        break;
      case "G642": // fall through
      case "G979":
        getContractDetails(period, wcmJurisdiction, newForm, wcmBusiness, frm)
        break;
}

见 Holger 的评论:

在 JDK 14 及更高版本中,您可以使用允许多个标签的新语法,而不会失败。

switch(form.formNumber) { 
  case "A1345", "B254" -> getExclusionDetails(account, state, form, businessDealing); 
  case "B297" -> getPartnershipDetails(account, state, form, businessDealing); 
  case "C397", "D972", "E192", "E299" -> getBrokerageDetails(account, state, form, businessDealing); 
  case "F254", "F795" -> getLocationDetails(account, state, form, businessDealing); 
  case "G642", "G979" -> getContractDetails(period, wcmJurisdiction, newForm, wcmBusiness, frm); 
}

【讨论】:

  • 在 JDK 14 及更新版本中,您可以使用允许多个标签的新语法,而不会失败。 switch(form.formNumber) { case "A1345", "B254" -> getExclusionDetails(account, state, form, businessDealing); case "B297" -> getPartnershipDetails(account, state, form, businessDealing); case "C397", "D972", "E192", "E299" -> getBrokerageDetails(account, state, form, businessDealing); case "F254", "F795" -> getLocationDetails(account, state, form, businessDealing); case "G642", "G979" -> getContractDetails(period, wcmJurisdiction, newForm, wcmBusiness, frm); }
【解决方案2】:

你可以把switch case换成if,else if,因为有多个条件相同的结果,这样会减少重复。

        var formDetails = new inferForms.buildFormsMap

        for(form in formDetails){
            var formNumber = form.formNumber
            if(formNumber.equals("A1345") || formNumber.equals("A1345")){
                getExclusionDetails(account, state, form, businessDealing)
            } else if (formNumber.equals("B297") || formNumber.equals("C397")) {
                getPartnershipDetails(account, state, form, businessDealing)
            } else if (formNumber.equals("D972") || formNumber.equals("E192")) {
                getBrokerageDetails(account, state, form, businessDealing)
            } else if (formNumber.equals("F254") || formNumber.equals("F795")) {
                getLocationDetails(account, state, form, businessDealing)
            } else if (formNumber.equals("G642") || formNumber.equals("G979")) {
                getContractDetails(period, wcmJurisdiction, newForm, wcmBusiness, frm)
            }
        }

【讨论】:

    【解决方案3】:

    对我来说,您的案例似乎是factory pattern 的理想人选。

    首先定义一个抽象来收集不同的细节。

    public interface DetailsManager {
    
      void gatherDetails(String account, String state, String form, String businessDealing);
    }
    

    继续具体实现。

    public class ExclusionDetailsManager implements DetailsManager {
    
      @Override
      public void gatherDetails(String account, String state, String form, String businessDealing) {
        //do stuff
      }
    }
    
    public class PartnershipDetailsManager implements DetailsManager {
    
      @Override
      public void gatherDetails(String account, String state, String form, String businessDealing) {
        //do other stuff
      }
    }
    

    为避免 switch 和 if-else 语句,您可以在工厂中使用 Map

    public class DetailsManagerFactory {
    
      private final Map<String, Supplier<DetailsManager>> map;
      private final Supplier<DetailsManager> defaultSupplier;
    
      public DetailsManagerFactory(Map<String, Supplier<DetailsManager>> map) {
        this.map = map;
        this.defaultSupplier = DefaultDetailsManager::new;
      }
    
      public DetailsManager getManager(String formNumber) {
        return this.map.getOrDefault(formNumber, this.defaultSupplier).get();
      }
    
      private static final class DefaultDetailsManager implements DetailsManager {
    
        @Override
        public void gatherDetails(String account, String state, String form, String businessDealing) {
          //default manager doing nothing, just making sure not to cause NPE
        }
      }
    }
    

    DetailsManager 的创建被 Supplier 包裹而延迟。如果对象是重量级的,这将很有用——实例仅在需要时创建。如果不需要,您可以将地图的值更改为DetailsManager

    public class CachingDetailsManagerSupplier implements Supplier<DetailsManager> {
    
      private final Supplier<DetailsManager> managerSupplier;
      private DetailsManager cache;
    
      public CachingDetailsManagerSupplier(Supplier<DetailsManager> managerSupplier) {
        this.managerSupplier = managerSupplier;
      }
    
      @Override
      public DetailsManager get() {
        if (this.cache == null) {
          //init manager
          this.cache = this.managerSupplier.get();
        }
        return this.cache;
      }
    }
    

    此供应商会缓存创建的实例,但根据您的具体用例,这可能是可取的/不需要的。

    例子

    //init factory where appropriate
    Supplier<DetailsManager> exclusionManagerSupplier = new CachingDetailsManagerSupplier(ExclusionDetailsManager::new);
    Map<String, Supplier<DetailsManager>> map = new HashMap<>();
    map.put("A1345", exclusionManagerSupplier);
    map.put("B254", exclusionManagerSupplier);
    map.put("B297", new CachingDetailsManagerSupplier(PartnershipDetailsManager::new));
    DetailsManagerFactory factory = new DetailsManagerFactory(map);
    
    //gather details
    for (Object form : formDetails) {
      String formNumber = form.formNumber;
      DetailsManager manager = factory.getManager(formNumber);
      manager.gatherDetails(account, state, form, businessDealing);
    }
    

    【讨论】:

      猜你喜欢
      • 2022-06-14
      • 1970-01-01
      • 2021-10-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多