2013-07-09 66 views
0

我遇到了实现策略模式的问题,这是我遇到的特定问题。依赖嵌套切换重构策略模式的方法

我基本上有一种方法进行值之间的比较。除了这两个值之外,这个方法依赖于两个额外的参数来确定我应该做哪个比较:一个运算符(等于,不等于,...)和一个类型(字符串,双精度)。它基本上是一个开关,它依赖于另一个交换机的结果。

让我用一个例子阐明:

public enum Type { 
    STRING, 
    BOOLEAN, 
    DOUBLE; 
} 
public enum Operator { 
    EQUALS(new Type[] { Type.STRING, Type.BOOLEAN}), 
    NOT_EQUALS(new Type[] { Type.STRING, Type.BOOLEAN}); 

    private Type[] allowedTypes; 

    Operator(Type[] allowedTypes) { 
     this.allowedTypes = allowedTypes; 
    } 

    public List<Type> getAllowedTypes() { 
     return Arrays.asList(allowedTypes); 
    } 
} 
public class Evaluator { 
    public Boolean evaluate(String value1, String value2, Operator operator, Type type) { 
     switch(operator) { 
      case EQUALS: 
       return doEqualComparison(value1, value2, type); 
     } 

     return null; 
    } 

    private Boolean doEqualComparison(String value1, String value2, Type type) { 
     //code here to check if the params are correct (not null, etc) 
     switch(type) { 
      case STRING: 
       return value1.equals(value2); 
      case DOUBLE: 
       return Double.parseDouble(value1) == Double.parseDouble(value2); 
     } 

     return null; 
    } 
} 

而且测试

public class EvaluatorTest { 
    @Test 
    public void testEvaluate() { 
     Evaluator evaluator = new Evaluator(); 

     // check STRING 
     Assert.assertTrue(evaluator.evaluate("100", "100", Operator.EQUALS, Type.STRING)); 
     Assert.assertFalse(evaluator.evaluate("100.00", "100", Operator.EQUALS, Type.STRING)); 

     // check DOUBLE 
     Assert.assertTrue(evaluator.evaluate("100", "100", Operator.EQUALS, Type.DOUBLE)); 
     Assert.assertTrue(evaluator.evaluate("100.00", "100", Operator.EQUALS, Type.DOUBLE)); 
    } 
} 

这工作得很好,但有两个(主要是嵌套的)switch语句似乎并不像一个非常干净和未来的证明解决方案,如果我们添加了很多类型和操作符,事情会变得很讨厌,很快,所以我的第一个事实是环是第一开关(操作员)更改为战略

public class EqualComparisonStrategy implements ComparisonStrategy { 
    @Override 
    public Boolean compare(String value1, String value2, Type Type) { 
     //HERE IS MY PROBLEM 
     switch (conditionType) { 
      case STRING: 
       return value1.equals(conditionValue); 
      case DOUBLE: 
       return Double.parseDouble(value1) == Double.parseDouble(value2); 
     } 

     return null; 
    } 

    @Override 
    public boolean accept(Operator operator) { 
     return operator == Operator.EQUAL; 
    } 
} 

尽管该解决方案是不是“太”坏我猜我想外部化第二开关(在我的评论是)太多,问题是,它的实施依赖于第一个(操作员)。 我想到了在accept方法

//snippet of the accept methode (instead of a factory) 
@Override 
public boolean accept(Operator operator, Type type) { 
    return operator == Operator.EQUAL && type == Type.STRING; 
} 

像StringEqualComparisonStrategy通过任何工厂或只是做一些更多的东西制成,但是这将创建M * N个战略和失控的真正快的(我有大约8运营商,与3种类型结果在24策略) 看到我希望这是一个未来证明尽可能这不是最好的解决方案恕我直言。

我确定必须有一个模式来解决这个问题,但我没有看到它。 (我不是模式英雄)

有人可以帮忙吗?

+1

如果您的'评估'方法总是以'字符串'作为输入,那么您为什么需要以不同的方式进行比较?我在想的是''3.1415“.equals(”3.1415“)'应该与'((Double)3.1415).equals((Double)3.1415)相同' – chancea

+0

因为我的示例代码演示了”40.0“吨等于“40”,而将其转换为双打将会。 字符串的考虑是因为它存储在数据库中 – Sem

回答

0

当我看到你的问题时,首先想到的是Decorator Pattern。 您可以用特定用例的必需功能来装饰非常基本的评估程序。尽管如此,你还是需要大量的装饰器,但如果你做得对,你可能会得到一个非常灵活的解决方案。

+0

虽然它看起来似乎装饰乍一看,在我看来,我从来没有**添加**行为的方法,但我宁愿**选择**的行为在前一个,这似乎不喜欢装饰(增加新的行为,而不修改现有)给我。 现在,这是一个事实,我不是模式英雄,但这就是我记得。 也许你可以用一个快速的(甚至伪代码就足够了)例子来阐述你的答案? – Sem