【发布时间】:2013-07-09 14:03:09
【问题描述】:
我在为遇到的特定问题实施策略模式时遇到问题。
我基本上有一种方法可以在值之间进行比较。除了这两个值之外,此方法还依赖两个附加参数来确定我应该进行哪个比较:一个运算符(等于、不等于、...)和一个类型(字符串、双精度) 它基本上是一个依赖于另一个开关结果的开关。
让我用一个例子来澄清一下:
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;
}
}
虽然该解决方案不是“太”糟糕,但我想我也想将第二个开关(我的评论所在的位置)外部化,但问题是它的实现依赖于第一个(操作员)。 我想到了像 StringEqualComparisonStrategy 这样的东西,要么由工厂制作,要么只是在接受方法中做更多的事情
//snippet of the accept methode (instead of a factory)
@Override
public boolean accept(Operator operator, Type type) {
return operator == Operator.EQUAL && type == Type.STRING;
}
但这会创建 M * N 策略并且很快就会失控(我有大约 8 个运算符,有 3 种类型,结果有 24 个策略) 看到我希望这是一个未来的证明,这不是最好的解决方案恕我直言。
我确信一定有一种模式可以解决这个问题,但我没有看到它。 (我不是模式英雄)
有人可以帮忙吗?
【问题讨论】:
-
如果您的
evaluate方法总是将Strings 作为输入,那么为什么需要对它们进行不同的比较?我在想的是"3.1415".equals("3.1415")应该和((Double)3.1415).equals((Double)3.1415)一样 -
正如我的示例代码所示,“40.0”不等于“40”,而将其转换为 Doubles 会。字符串考虑是因为它存储在数据库中
标签: java design-patterns switch-statement strategy-pattern