2012-03-14 39 views
3

我認爲以下可能非常適合策略模式,但我不確定這是否正確,如果是這樣,如何正確實施。代碼異味 - 哪種設計模式以及如何實現?

我有一個方法,將接受一個類別和一個排序。目前Category和Sort是枚舉,所以像這樣:

public enum Category{ 
    Hot, 
    New 
} 

public enum Sort{ 
    New, 
    Rising,  
    ThisWeek 
} 

public String getUrl(Category category, Sort sort){ 
    validateCategorySortCombo(category, sort); 
} 

注意validateCategorySortCombo(Category,Sort)。首先,我必須驗證類別+排序的組合 ,因爲有些是無效的。例如:

if(Category == "Hot" && Sort == "Rising"){ 
    ThrowInvalidCategorySortCombo("Can't use hot category with rising sort") 
} 

將會有幾個這些檢查以確保組合是有效的。這看起來像是一種代碼味道,因爲隨着其他類別和排序的介紹,我將不得不打開這個類並修改它打破/關閉原則。

當我必須檢查Category和Sort來構造我的Url並傳回時,第二個代碼會出現異味。目前我使用了一系列switch語句:

String url; 
switch(category){ 
    case Hot: 
    url += "www.site.com/hot/"; 
    case New: 
    url += "www.site.com/new/"; 
} 

switch(sort){ 
    case New: 
    url += "?sort=rising"; 
    case ThisYear: 
    url += "?sort=thisyear"; 
} 

再次,新的類別和種類的介紹,我會打開這個類,並更新switch語句。

幾個問題:

  1. 什麼樣的設計模式將被用來解決我的問題?
  2. 我將如何去實施設計模式?

回答

3

首先,我建議你離開你的心胸開闊,以多種設計模式,直到你寫一些代碼。允許您的代碼告訴您哪種模式最適合。如果您事先選擇一個,最終可能會試圖「強制」您的代碼使用可能不是最佳選項的模式。

說了這麼多,一些可能最終會在您的情況下有用的模式將是戰略和Chain of Responsibility

談完...

我認爲你需要退後一步,拿出你的設計目標是基於你如何期望系統隨時間而改變。例如,聽起來你確實希望添加新的類別和排序。在此基礎上,兩球您的設計可能會是:

  1. 添加新的排序/分類
  2. 減少添加新的排序時,網址的建築規範的修改時,最小化的修改,以驗證代碼/分類

從這些目標出發,提出一個通用的方法。例如,我的想法是......

  1. 如果我將每個驗證分成它自己的類,那麼在添加新的分類/排序時,我不需要修改現有的驗證算法。我所要做的就是添加新的驗證算法,或者如果不再適用,可能會刪除現有的驗證算法。 (這可能是矯枉過正,但我​​不知道你的驗證算法是多麼複雜或將會得到)
  2. 如果每個分類/排序知道如何提供它自己的url部分,每個新的類別或排序應該沒有影響關於獲取現有類別或排序的url表示的能力。

現在你可以開始思考更多關於實現(你有很多選擇)。例如,你可以擴大你的枚舉,以便每個值已經知道它的URL部分,像這樣:

​​

走這條路,你可以隨時撥打mySort.getUrlComponent(),它不需要添加/刪除排序枚舉時改變值。這將特別解決您的第二個問題。

我不能爲您提供最佳實施方案或一組設計模式,因爲我不知道您所做的關於您正在構建的系統的所有內容,但是我希望我的想法能夠幫到您。

1

只需將排序順序的驗證移動到您的類別枚舉。因此,它讀取category.isValidSort(sort);

2

像中號Platvoet說:

import java.util.*; 
enum Category { 
    Hot(EnumSet.of(Sort.Rising)),New(EnumSet.of(Sort.ThisWeek,Sort.ThisYear)); 
    Category(EnumSet<Sort> legal) { 
     this.legal.addAll(legal); 
    } 
    boolean isLegal(Sort sort) { 
     return legal.contains(sort); 
    } 
    private final EnumSet<Sort> legal=EnumSet.noneOf(Sort.class); 
} 
enum Sort { 
    New,Rising,ThisWeek,ThisYear; 
} 
public class So9706550 { 
     static boolean isValid(Category category,Sort sort) { 
      return category.isLegal(sort); 
    } 
    public static void main(String[] args) { 
     System.out.println(isValid(Category.Hot,Sort.Rising)); 
     System.out.println(isValid(Category.Hot,Sort.ThisWeek)); 
    } 
} 
0

對於你的第一個擔憂 -

您可以定義哪些具體可以是一個驗證一個hashmap,其關鍵是分類和排序的成分。

你可以預先用有效組合填充這張地圖[可以考慮硬編碼/配置文件驅動/定期刷新等]。

在你的validateCategorySortCombo你可以檢查hashmap是否實際包含密鑰?如果是的話,很好去。

-

Map<Compositekey<Sort,Category>,Boolean> validOptions = new hashMap.. 

void validateCategorySortCombo(category, sort){ 

    if(validOptions.containskey(category,sort)){ 
    //good to go 
    } 
} 
0

我注意到,你沒有,只確認輸入,但撰寫基於這些URL字符串。 雖然看起來像Abstract Factory的經典案例可能有點過度使用。 您可能具有類別的抽象系列和具體實現SortedCategories。 其他好處是,您可以在HotRaisedFactory中明確引發異常,作爲該類別和Sort的不可接受的組合。