依赖嵌套切换重构为策略模式的方法

时间:2013-07-09 14:03:09

标签: java design-patterns switch-statement strategy-pattern

我遇到的问题是针对我遇到的特定问题实施策略模式。

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

让我用一个例子来澄清:

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或者在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;
}

但是这会产生M * N策略并且快速失控(我有大约8个运营商,有3种类型,结果有24种策略)     看来我希望这可能是未来的证据,这不是恕我直言的最佳解决方案。

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

有人可以帮忙吗?

1 个答案:

答案 0 :(得分:0)

当我读到你的问题时,我脑海中浮现的第一件事是装饰模式。 您可以使用特定用例所需的功能来装饰一个非常基本的Evaluator。不过,你需要相当数量的装饰者,但如果你做得对,你可能会得到一个非常灵活的解决方案。