代码气味 - 哪种设计模式以及如何实现?

时间:2012-03-14 17:02:52

标签: java oop design-patterns

我认为以下内容可能非常适合策略模式,但我不确定这是否正确,如果是,那么如何正确实施。

我有一个接受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. 我将如何实施设计模式?

5 个答案:

答案 0 :(得分:3)

首先,我建议您在编写一些代码之前,先想到多种设计模式。允许您的代码告诉您哪种模式最有效。如果你事先选择一个,你最终可能会试图“强迫”你的代码使用一个可能不是最佳选择的模式。

话虽如此,在您的情况下可能最终有用的几种模式将是策略和Chain of Responsibility

继续......

我认为您需要退后一步,根据您对系统随时间变化的预期,提出您的设计目标。例如,听起来你肯定期望添加新的类别和排序。基于此,您的设计可能有两个目标:

  1. 在添加新的排序/类别时最小化对验证代码的修改
  2. 在添加新的排序/类别
  3. 时最小化对网址构建代码的修改

    从这些目标出发,提出一种通用的方法。例如,我的想法是......

    1. 如果我将每个验证分成它自己的类,我在添加新的Category / Sort时不需要修改现有的验证算法。我所要做的就是添加新的验证算法,如果不再适用,可能会删除现有的验证算法。 (这可能有点矫枉过正,但我​​不知道您的验证算法有多复杂或将会得到)
    2. 如果每个类别/排序都知道如何提供自己的网址,则每个新类别或排序都不应影响获取现有类别或排序的网址表示的能力。
    3. 现在你可以开始考虑更多关于实现的问题(你有很多选择)。例如,您可以扩展枚举,以便每个值都已知道其url组件,如下所示:

      public enum Sort{
        New("?sort=new"),
        Rising("?sort=rising"),      
        ThisWeek("?sort=thisweek");
      
      
        private String urlComponent;
        public Sort(String urlComponent) {this.urlComponent = urlComponent;)
        public getUrlComponent() {return this.urlComponent;}
      }
      

      走这条路线,你总是可以调用mySort.getUrlComponent(),这在添加/删除Sort枚举值时不需要改变。这将特别解决您的第二个问题。

      我不能给你最好的实现或一组设计模式,因为我不知道你对你正在构建的系统所做的一切,但我希望我的想法会有所帮助。

答案 1 :(得分:2)

像M 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));
    }
}

答案 2 :(得分:1)

只需将排序顺序的验证移至类别枚举即可。所以它显示为category.isValidSort(sort);

答案 3 :(得分:0)

第一个问题 -

您可以定义一个特别是hashmap的验证器,其密钥将是Category和Sort的组合。

您可以使用有效组合预先填充此地图[可以考虑硬编码/配置文件驱动/定期刷新等]。

validateCategorySortCombo中,您可以检查散列图是否实际包含密钥?如果是的话,那就好了。

-

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

void validateCategorySortCombo(category, sort){

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

答案 4 :(得分:0)

我注意到您不仅验证了输入,还根据它们编写了一个URL字符串。 虽然看起来像Abstract Factory的经典案例,但它可能有点过度使用。 您可能拥有类别的抽象族和具体实现SortedCategories。 其他好处是您可以在HotRaisedFactory中明确地将异常引发为该类别和Sort的不可接受的组合。