2009-11-10 94 views
0

请重构此代码建议。 避免代码重复,多发性如果的如何重构此代码?

public FormDataDTO getDataForFieldFormCHrzntalField(Field field) { 
     FormDataDTO formDataDTO = new FormDataDTO(); 
     CHrzntalField cHrzntalField = (CHrzntalField) field; 
     for (int j = 0; j < cHrzntalField.getFieldCount(); j++) { 
      Field sField = cHrzntalField.getField(j); 
      if (sField instanceof LabelField) { 
       LabelField labelField = sField; 
       String fieldName = labelField.getText(); 
       System.out.println("The Label field name is " + fieldName); 
       formDataDTO.setFieldName(fieldName); 
      } else if (sField instanceof CTextFieldBorder) { 
       CTextFieldBorder cTextFieldBorder = (CTextFieldBorder) sField; 
       Field ssField = cTextFieldBorder.getField(0); 
       if (ssField instanceof TextField) { 
        TextField textField = ssField; 
        System.out.println("Inside TextField---- " 
          + textField.getText()); 
        formDataDTO.setFieldType("TextField"); 
        formDataDTO.setSelectedValue(textField.getText()); 
       } else if (ssField instanceof DateField) { 
        DateField dateField = ssField; 
        String dateString = dateField.toString(); 
        System.out.println("dateString " + dateString); 
        formDataDTO.setFieldType("Date"); 
        formDataDTO.setSelectedValue(dateString); 
       } 
      } else if (sField instanceof CChoiceField) { 
       CChoiceField cChoiceField = (CChoiceField) sField; 
       int i = cChoiceField.getSelectedIndex(); 
       String selectedValue = cChoiceField.getChoice(i); 
       System.out.println("Choice " + selectedValue); 
       formDataDTO.setFieldType("Combo"); 
       formDataDTO.setSelectedValue(selectedValue); 
      } else if (sField instanceof CheckboxField) { 
       CheckboxField checkboxField = (CheckboxField) sField; 
       boolean checkStatus = checkboxField.getChecked(); 
       System.out.println("Check box field " + checkStatus); 
       formDataDTO.setFieldType("Checkbox"); 
       String status = new Boolean(checkStatus).toString(); 
       formDataDTO.setSelectedValue(status); 
      } 
     } 
     return formDataDTO; 
    } 
+1

这个问题的感觉是它应该在编码考试中。 'Refactor-my-code'标签有点让人失望,你似乎在要求别人为你做你的工作。 – 2009-11-10 09:45:23

+0

提示/建议是我所期待的。我只是使用现有的标签。 :) – HanuAthena 2009-11-10 09:54:50

+0

我没有看到问题的任何问题。首先,他要求_suggestions_重构代码。这不是问题说“我需要写一个应用程序到xyz,请给我发送codez”。也许一旦解决方案被确定,可以将该问题编辑为“将xxx重构为yyy”以备将来参考。 – Kirschstein 2009-11-10 09:55:24

回答

4

第一步是建立一个单元测试验证了该方法的行为。其次,“告诉,不要问”是一个很好的面向对象设计的原则,所以如果你能够重构Field类型及其子类,实现一种允许他们在FormDataDTO上设置必要信息的方法,那将是一件好事。

+0

欢迎来到SO :) – HanuAthena 2009-11-10 10:07:03

3

您可以通过拉动每种情况下开始块(内码的if/else if块)到自己的方法。我看不到很多重复,只是试图用一种方法做太多。

0

您应该使用方法重载避免的instanceof电话。应将每个if (sField instanceof ...)移动到采用所需类型作为参数的单独方法。

+0

这是行不通的,因为该方法是在编译时选取的,并且会采用“Field”参数。你需要施放。 – Stroboskop 2009-11-10 09:50:46

+0

Stroboskop是正确的 - 但是,更好的做法是创建Field的子类并在其中实现逻辑。覆盖,而不是过载;问,不要告诉。 – 2009-11-10 12:05:27

2

您可以应用从它的外观的策略模式;

  • 创建你上的所有字段调用方法的界面,说FieldHandler
  • 初始化从类名的地图FieldHandler你需要覆盖(如LabelFieldHandler,DateFieldHandler等)
  • 每场型含实现在函数doXXX中,而不是使用instanceOf来为每个字段类型执行variantions,请在您的映射中查找相应的处理程序,并将调用委托给处理程序。

伪代码:

field = getField(j); 
handler = handlerMap.get(field.className); 
if (null == handler) { 
    // error unknown field type 
} else { 
    handler.setFormData(field, formDataDTO); 
} 
1

在字段

public class Field { 
    public abstract void updateFormData(FormDataDTO formDataDTO); 
} 

添加新的抽象方法,然后,实现它在场的每个子类。

最后,你的代码就变成了:

public FormDataDTO getDataForFieldFormCHrzntalField(Field field) { 
    FormDataDTO formDataDTO = new FormDataDTO(); 
    CHrzntalField cHrzntalField = (CHrzntalField) field; 
    for (int j = 0; j < cHrzntalField.getFieldCount(); j++) { 
      Field sField = cHrzntalField.getField(j); 
      sField.updateFormData(formDataDTO); 
    } 
    return formDataDTO; 
} 
+0

这将是一个解决方案,除非Field类型不是项目的一部分,而是封装框架的一部分。 – rsp 2009-11-10 11:45:57

+0

是的,确切地说。 (在两个方面:rsp都有一个点) – CPerkins 2009-11-10 11:58:07

+0

ok,那么你可以使用相同的东西,但是使用一个新的FieldWrapper接口,它将封装Field实例,并且可以使用工厂或策略模式创建。 – Lastnico 2009-11-10 13:17:16

1

你需要派遣字段类型。有这样做的各种方式:

  1. 如果使用显式测试类的语句。

  2. 使所有字段实现一个接口,为每个字段类型适当地实现该接口,然后调用接口。

  3. 使用地图查找该课程的相应操作。

选项1是你现在正在做什么; 2是Stroboskop提到的; 3被rsp称为策略模式。正如你所看到的,1有点混乱。 2将上述方法的工作与领域耦合,而3不是。选择哪个(2或3个)取决于您的具体情况。 (2)的一个优点是你不会忘记为每个新字段编写代码(因为如果你忘记了,你会得到一个编译器错误)。 (3)的优点是,如果你想多次做这种事情,这些领域可能会变得混乱。另外,(2)要求您有权访问字段代码。值得注意的是,如果您使用的是Scala而不是Java,则(2)中的某些问题可以避免使用特征(并且它对(1)模式匹配也有更好的语法)。

我个人更喜欢(2)如果可能的话 - 也许可以通过授权来实现它。 (3)与(1)相比唯一的优点是代码更简洁 - 并且有一些额外的类型安全性。