2009-11-10 91 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)相比唯一的優點是代碼更簡潔 - 並且有一些額外的類型安全性。