ネストされた場合はelseとスイッチ文とリファクタリングコードへのデザインパターン

Shailesh Saxena:

私はかさばる既存のコードをリファクタリングする必要があります。SOおよび他のサイトで同様の質問の多くを経て、まだ混乱。誰もがいくつかの光を入れたりすることができた場合はすべてのアイデアは、大きな助けになるだろう。

そこ5つのドロップダウンがあると私はドロップダウンでslected値に基づいてビューを更新する必要があります。最初のドロップダウンには、次のオプションがあります。

"TOP DOWN BUDGET"
"TEMPLATE BUDGET"
"ORIGINAL BUDGET"
"REVISED BUDGET"

第二に、ドロップダウンには、次のオプションがあります。

"Day"
"Week"
"Month"
"Quarter"
"Year"

第三に、ドロップダウンには、次のオプションがあります。

"Details"
"Summary"

第四に、ドロップダウンには、次のオプションがあります。

"Hours"
"Dollars"

第五に、ドロップダウンには、次のオプションがあります。

 "StartDate"
 "EndDate"

今のコードでは、シナリオ、以下があります。

public List<WorkPlanReport> XYZ(...){//opening of some method XYZ....

List<WorkPlanReport> workPlanReportList=null;
switch(first_Drop_Down_Value){

    case "TOP DOWN BUDGET":
        List<TaskDetails> timeLine=getTimeLine("firstDropDownA", second_drop_down_val, third_drop_down_val, fourth_drop_down_val);
        workPlanReportList=setWorkPlanByTimeLine(timeLine, "firstDropDownA", second_drop_down_val, third_drop_down_val, fourth_drop_down_val);
        break;
    case "TEMPLATE BUDGET":
        List<TaskDetails> timeLine=getTimeLine("firstDropDownB", second_drop_down_val, third_drop_down_val, fourth_drop_down_val, fifth_dd_val);
        workPlanReportList=setWorkPlanByTimeLine(timeLine, "firstDropDownA", second_drop_down_val, third_drop_down_val, fourth_drop_down_val);
        break;
    case "ORIGINAL BUDGET":
        List<TaskDetails> timeLine=getTimeLine("firstDropDownC", second_drop_down_val, third_drop_down_val, fourth_drop_down_val, fifth_dd_val);
        workPlanReportList=setWorkPlanByTimeLine(timeLine, "firstDropDownA", second_drop_down_val, third_drop_down_val, fourth_drop_down_val);
        break;
    case "REVISED BUDGET":
        List<TaskDetails> timeLine=getTimeLine("firstDropDownD", second_drop_down_val, third_drop_down_val, fourth_drop_down_val, fifth_dd_val);
        workPlanReportList=setWorkPlanByTimeLine(timeLine, "firstDropDownA", second_drop_down_val, third_drop_down_val, fourth_drop_down_val);
        break;

}

return workPlanReportList;
}// Closing of some method XYZ....

private List<TaskDetails> getTimeLine(String first_Drop_Down_Value, String second_dd_val, third_dd_val, fourth_dd_val, String fifth_dd_val){

    switch(second_Drop_Down_Value){

    case "Day":
        if(third_dd_val.equals("Details")){
            if(fourth_dd_val.equals("Hours")){
                if(fifth_dd_val.equals("startDate"){
                //prepare query & call DB for fetching days timeline for hours details of TOP DOWN BUDGET filtered by start date...
                }
                else// means endDate{
                //prepare query & call DB for fetching days timeline for hours details of TOP DOWN BUDGET filtered by end date...
                }
            }
            else{//means Dollars
                if(fifth_dd_val.equals("startDate"){
                //prepare query & call DB for fetching days timeline for dollars details of TOP DOWN BUDGET filtered by start date...
                }
                else// means endDate{
                //prepare query & call DB for fetching days timeline for dollars details of TOP DOWN BUDGET filtered by end date...
                }
            }   
        }
        else// means summary...
        {
            if(fourth_dd_val.equals("Hours")){
                if(fifth_dd_val.equals("startDate"){
                //prepare query & call DB for fetching days timeline for 'hours' "summary" of TOP DOWN BUDGET filtered by start date...
                }
                else// means endDate{
                //prepare query & call DB for fetching days timeline for hours summary of TOP DOWN BUDGET filtered by end date...
                }
            }
            else{//means Dollars
                if(fifth_dd_val.equals("startDate"){
                //prepare query & call DB for fetching days timeline for dollars details of TOP DOWN BUDGET filtered by start date...
                }
                else// means endDate{
                //prepare query & call DB for fetching days timeline for dollars details of TOP DOWN BUDGET filtered by end date...
                }
            }
        }
        break;
    case "Week":
            //....similar code as in case "Day" just here we need to fetch data week-wise
            break;
    case "Month":
            //....similar code as in case "Day" just here we need to fetch data month-wise
            break;
    case "Quarter":
            //....similar code as in case "Day" just here we need to fetch data quarter-wise
            break;
    case "Year":
            //....similar code as in case "Day" just here we need to fetch data year-wise
            break;
    }
}


private List<WorkPlanReport> setWorkPlanByTimeLine(List<TaskDetails> timeLine, String "firstDropDownA", String second_drop_down_val, String third_drop_down_val, String fourth_drop_down_val){

WorkPlanReport wpr=new WorkPlanReport();
// Here I have real mess..., Iterating the timeLine list and have switch case and inside switch case multilevel nesting of if else to decide which setter we need to use to set the value.

for example:

If it is "TOP DOWN BUDGET" in first drop-down, "Day" in second drop-down, "Details" in third drop down, "Hours" in fourth drop-down & "StartDate" in fifth drop-down, I have to call follwing code:

wpr.setTDBDetailsHoursByStartDate(taskDetails.getTDBDetailsByHourStartDayView());

If it is "TOP DOWN BUDGET" in first drop-down, "Day" in second drop-down, "Details" in third drop down, "Hours" in fourth drop-down & "EndDate" in fifth drop-down, I have to call follwing code:
wpr.setTDBDetailsHoursByEndDate(taskDetails.getTDBDetailsByHourEndDayView());

}

このコードは、1000本の以上のラインである、と私はいくつかの適切な設計パターンを使用して、それをリファクタリングするdeseparateています。

WorkPlanReport&TaskDetailsのDTOは、共通のプロパティのいくつかの類似したタイプや他の多くの異なった性質を持っています。

私はそれらをいくつかの関連する共通のコードベースで使用されているので、それらのDTOを変更することは許されないのです。

編集:これは、このコードで使用されている方法です。私はそれを簡単にするために最善の私のレベルを試してみましたが、どの作業のアイデアを思い付くことができませんでした。

private void setSummaryColumns(String DolOrHr, String columnFilter,
            Map<String, String> filterBy, Object[] obj,
            WorkplanReport workplanReport, TemplateDump td) {
        switch(filterBy.get(columnFilter)){
        case "TOP DOWN":
            td.setTopDownBudgetStartDate(obj[1] != null ? (Date)obj[1]:null);
            td.setTopDownBudgetEndDate(obj[2] != null ? (Date)obj[2]:null);
             workplanReport.setStartDatebyMajorMeasure(obj[1] != null ? obj[1].toString():"-");
             workplanReport.setEndDatebyMajorMeasure(obj[2] != null ? obj[2].toString():"-");
             workplanReport.setDolorHrsbyMajorMeasure(obj[3] != null ? obj[3].toString():"-");
            if(DolOrHr.equals("BudgetDollars"))
                td.setTopDownBudgetDollars(obj[3] != null ? (BigDecimal)obj[3]:null);

            else
                td.setTopDownBudgetHours(obj[3] != null ? (BigDecimal)obj[3]:null);
            break;
        case "TEMPLATE":
            td.setTemplateBudgetStartDate(obj[1] != null ? (Date)obj[1]:null);
            td.setTemplateBudgetEndDate(obj[2] != null ? (Date)obj[2]:null);
            workplanReport.setStartDatebyTemplateBudget(obj[1] != null ? obj[1].toString():"-");
            workplanReport.setEndDatebyTemplateBudget(obj[2] != null ? obj[2].toString():"-");
            workplanReport.setDolorHrsbyTemplateBudget(obj[3] != null ? obj[3].toString():"-");
            if(DolOrHr.equals("BudgetDollars"))
                td.setTemplateBudgetDollars(obj[3] != null ? (BigDecimal)obj[3]:null);
            else
                td.setTemplateBudgetHours(obj[3] != null ? (BigDecimal)obj[3]:null);
            break;
        case "ORIGINAL":
            td.setOriginalBudgetStartDate(obj[1] != null ? (Date)obj[1]:null);
            td.setOriginalBudgetEndDate(obj[2] != null ? (Date)obj[2]:null);
            workplanReport.setOrgStartDate(obj[1] != null ? obj[1].toString():"-");
            workplanReport.setOrgEndDate(obj[2] != null ? obj[2].toString():"-");
            workplanReport.setOrgBudgetedDollarsHours(obj[3] != null ? obj[3].toString():"-");
            if(DolOrHr.equals("BudgetDollars"))
                td.setOriginalBudgetDollars(obj[3] != null ? (BigDecimal)obj[3]:null);
            else
                td.setOriginalBudgetHours(obj[3] != null ? (BigDecimal)obj[3]:null);
            break;
        case "REVISED":
            td.setRevisedBudgetStartDate(obj[1] != null ? (Date)obj[1]:null);
            td.setRevisedBudgetEndDate(obj[2] != null ? (Date)obj[2]:null);
            workplanReport.setRevStartDate(obj[1] != null ? obj[1].toString():"-");
            workplanReport.setRevEndDate(obj[2] != null ? obj[2].toString():"-");
            workplanReport.setRevBudgetedDollarsHours(obj[3] != null ? obj[3].toString():"-");
            if(DolOrHr.equals("BudgetDollars"))
                td.setRevisedBudgetDollars(obj[3] != null ? (BigDecimal)obj[3]:null);
            else
                td.setRevisedBudgetHours(obj[3] != null ? (BigDecimal)obj[3]:null);
            break;

        case "MANAGER":

            td.setManagerBudgetStartDate(obj[1] != null ? (Date)obj[1]:null);
            td.setManagerBudgetEndDate(obj[2] != null ? (Date)obj[2]:null);
            workplanReport.setStartDatebyManagersRevised(obj[1] != null ? obj[1].toString():"-");
            workplanReport.setEndDatebyManagersRevised(obj[2] != null ? obj[2].toString():"-");
            workplanReport.setDolorHrsbyManagersRevised(obj[3] != null ? obj[3].toString():"-");
            if(DolOrHr.equals("BudgetDollars"))
                td.setManagerBudgetDollars(obj[3] != null ? (BigDecimal)obj[3]:null);
            else
                td.setManagerBudgetHours(obj[3] != null ? (BigDecimal)obj[3]:null);
            break;
        case "ACTUAL":
            td.setActualBudgetStartDate(obj[1] != null ? (Date)obj[1]:null);
            td.setActualBudgetEndDate(obj[2] != null ? (Date)obj[2]:null);
            workplanReport.setStartDatebyActual(obj[1] != null ? obj[1].toString():"-");
            workplanReport.setEndDatebyActual(obj[2] != null ? obj[2].toString():"-");
            workplanReport.setDolorHrsbyActual(obj[3] != null ? obj[3].toString():"-");
            if(DolOrHr.equals("BudgetDollars"))
                td.setActualBudgetDollars(obj[3] != null ? (BigDecimal)obj[3]:null);
            else
                td.setActualBudgetHours(obj[3] != null ? (BigDecimal)obj[3]:null);
            break;
        }
    }
davidxxx:

あなたは、実際のコードで多くのものを複製します。
あなたが使用できるパターンを考える前に、私は実際の削除を開始することをアドバイス本当の問題アンチパターンであるコードの重複を:。

マイナーのDUPは、最初のレベルのあるswitch声明:

case "TOP DOWN BUDGET":
    List<TaskDetails> timeLine=getTimeLine("firstDropDownA", second_drop_down_val, third_drop_down_val, fourth_drop_down_val);
    workPlanReportList=setWorkPlanByTimeLine(timeLine, "firstDropDownA", second_drop_down_val, third_drop_down_val, fourth_drop_down_val);
    break;
case "TEMPLATE BUDGET":
    List<TaskDetails> timeLine=getTimeLine("firstDropDownB", second_drop_down_val, third_drop_down_val, fourth_drop_down_val, fifth_dd_val);
    workPlanReportList=setWorkPlanByTimeLine(timeLine, "firstDropDownA", second_drop_down_val, third_drop_down_val, fourth_drop_down_val);
    break;
 ...

ほとんどすべての複製されます。単一の変異体の事はに渡される最初のパラメータですgetTimeLine()
あなたが使用する文字列を交換しswitchて文Budget列挙し、この部分が短いとしても考えられます。

Budget budget = Budget.valueOf(first_Drop_Down_Value);

List<TaskDetails> timeLine=getTimeLine(budget.getValueForTimeLine(), second_drop_down_val, third_drop_down_val, fourth_drop_down_val);
workPlanReportList=setWorkPlanByTimeLine(timeLine, "firstDropDownA", second_drop_down_val, third_drop_down_val, fourth_drop_down_val);

そして、一見大きな重複がに位置していますgetTimeLine()
あなたが複製し、どこで単一の実の違いは、あなたが渡すことができるパラメータであることをそれぞれの事についてまったく同じレシピを適用することができます。
だからではなく、2番目のドロップダウン(「日」「週」、「月」、「四半期」、「年」)の可能性に切り替えるのにこの情報を伝えるために列挙型をご紹介:

TimePeriod timePeriod = TimePeriod.valueOf(second_Drop_Down_Value);

第三のドロップダウン(「詳細」と「概要」)のために同じことを行います。

DetailLevel detailLevel = DetailLevel.valueOf(third_Drop_Down_Value);

そして、の粒度を変更する方法を与えることに応じてフェッチTimePeriodDetailLevel選択。それだけでデータを取得する方法で渡された2つのパラメータになります。

ここにあなたのリファクタリングタスクを停止することにより、getTimeLine()ルックスは本当に短くて単純好き:

private List<TaskDetails> getTimeLine(String first_Drop_Down_Value, String second_dd_val, third_dd_val, fourth_dd_val, String fifth_dd_val){

    TimePeriod timePeriod = TimePeriod.valueOf(second_Drop_Down_Value);
    DetailLevel detailLevel = DetailLevel.valueOf(third_Drop_Down_Value);

    if(fourth_dd_val.equals("Hours")){
        if(fifth_dd_val.equals("startDate"){           
          fetch(...,....,timePeriod, detailLevel) // <- pass the enums
        }
        else// means endDate{
        //prepare query & call DB for fetching days timeline for hours details of TOP DOWN BUDGET filtered by end date...
          fetch(...,....,timePeriod, detailLevel) // <- pass the enums
        }
    }
    else{//means Dollars
        if(fifth_dd_val.equals("startDate"){
        //prepare query & call DB for fetching days timeline for dollars details of TOP DOWN BUDGET filtered by start date...
          fetch(...,....,timePeriod, detailLevel) // <- pass the enums
        }
        else// means endDate{
        //prepare query & call DB for fetching days timeline for dollars details of TOP DOWN BUDGET filtered by end date...
          fetch(...,....,timePeriod, detailLevel) // <- pass the enums
        }
    }   
}

編集します

あなたがの例で明確なセッターを呼び出す部分についてswitch声明、あなたはまだあなたがくくり出すことができ、多くの類似点を持っています。
「トップダウン」と「ORIGINAL」:例で例を取ります:

td.setTopDownBudgetStartDate(obj[1] != null ? (Date)obj[1]:null);
td.setTopDownBudgetEndDate(obj[2] != null ? (Date)obj[2]:null);

td.setOriginalBudgetStartDate(obj[1] != null ? (Date)obj[1]:null);
td.setOriginalBudgetEndDate(obj[2] != null ? (Date)obj[2]:null);

その後:

workplanReport.setStartDatebyMajorMeasure(obj[1] != null ? obj[1].toString():"-");
workplanReport.setEndDatebyMajorMeasure(obj[2] != null ? obj[2].toString():"-");
workplanReport.setDolorHrsbyMajorMeasure(obj[3] != null ? obj[3].toString():"-");

対 :

workplanReport.setOrgStartDate(obj[1] != null ? obj[1].toString():"-");
workplanReport.setOrgEndDate(obj[2] != null ? obj[2].toString():"-");
workplanReport.setOrgBudgetedDollarsHours(obj[3] != null ? obj[3].toString():"-");

そしてそのために...

最後に、同じ論理が適用されるが、計算は同じセッターに割り当てられていないWorkPlanReportTemplateDumpオブジェクト。
WorkPlanReportそしてTemplateDumpこれらは、それらの間に関連しているため、さらには特定のクラスに抽出する必要がある可能性があり、個々のフィールドの多くのクラスとして表示されます。それは、高凝集の原理です。

「TOP DOWN」ダンプたとえば、あなたが定義することができます。

public class TopDownTemplateDump {
    private Date budgetStartDate;
    private Date budgetEndDate;
    private BigDecimal budgetDollars;
    private BigDecimal budgetHours;
    // and so for ...
    // setters - getters 
}

「ORIGINAL」ダンプのために、あなたが定義することができます。

public class OriginalTemplateDump {
    private Date budgetStartDate;
    private Date budgetEndDate;
    private BigDecimal budgetDollars;
    private BigDecimal budgetHours;
    // and so for ...
    // setters - getters
}     

そして、TemplateDumpそれぞれの「ダンプ・パート」を保持していることは、今のようになります。

public class TemplateDump {
   private TopDownTemplateDump topDownTemplateDump;
   private OriginalTemplateDump originalTemplateDump;
   ...
}

彼らはまったく同じ構造を所有する一方、しかし、それは、これらすべての「ダンプ」のクラスを複製する意味がありませんか?あんまり。
おそらく、基底クラスにそれらを取り出す必要があります。

public abstract class AbstractTemplateDump {
    private Date budgetStartDate;
    private Date budgetEndDate;
    private BigDecimal budgetDollars;
    private BigDecimal budgetHours;
    // and so for ...
    // setters - getters
}       

具体的な部分は、今から継承することができますAbstractTemplateDumpよう:

public class TopDownTemplateDump extends AbstractTemplateDump{
    // add subclass specifities here
}

今、あなたはのデータ設定する統一的な方法持つTemplateDumpインスタンスを。だから、switchもはや必要とされていません。
以下のためにまったく同じロジックに従ってくださいWorkPlanReport

あなたのコードは次のようになります。

AbstractTemplateDump absTd = td.getDumpPart(filterBy.get(columnFilter));
AbstractReportPart absRp = workplanReport.getReportPart(filterBy.get(columnFilter));

absTd.setBudgetStartDate(obj[1] != null ? (Date)obj[1]:null);
absTd.setBudgetEndDate(obj[2] != null ? (Date)obj[2]:null);
absRp.setStartDateby(obj[1] != null ? obj[1].toString():"-");
absRp.setEndDateby(obj[2] != null ? obj[2].toString():"-");
absRp.setDolorHrsby(obj[3] != null ? obj[3].toString():"-");
// ...

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=204940&siteId=1