Стратегия паттерна против переключателя ИЛИ Как справиться с большим количеством различных операций

Я хочу избавиться от Switch с разными операциями в коде. Можно ли это сделать с помощью паттерна Стратегия в данном случае (или есть другой способ?):

public interface Strategy {
    BigDecimal minus(BigDecimal a, BigDecimal b);
    BigDecimal sum(BigDecimal a, BigDecimal b);
    BigDecimal pow(BigDecimal a, int n);
}

public class Minus implements Strategy {
    public BigDecimal minus(BigDecimal a, BigDecimal b) {
        return a.subtract(b);
    }
}

public class Sum implements Strategy{
    public BigDecimal sum(BigDecimal a, BigDecimal b) {
        return a.add(b);
    }

    public BigDecimal pow(BigDecimal a, int n) {
        return a.pow(n);
    }
}

public class Calc {
    private Strategy strategy;
    private BigDecimal a;
    private BigDecimal b;
    private int n;

    public Calc(Strategy strategy, BigDecimal a, BigDecimal b, int n) {
        this.strategy = strategy;
        this.a = a;
        this.b = b;
        this.n = n;
    }

    public void calculate(String operation) {
        switch (operation) {
            case "SUM":
                strategy.sum(a, b);
                break;
            case "POW":
                strategy.pow(a, n);
                break;
            case "MINUS":
                strategy.minus(a, b);
        }
    }
}

ps: код не работает, потому что я не понимаю, как реализовать интерфейс Strategy, не удаляя метод pow из класса Sum.


person Айдар Хусаинов    schedule 19.01.2021    source источник


Ответы (1)


У вас какое-то непонимание по поводу паттерна стратегии. Проще говоря, реализуя его, вы получаете классы, каждый из которых обеспечивает особое проявление поведения. Затем вы выбираете из всех этих возможных проявлений, какое из них использовать для вашего конкретного случая. Стратегия вашего интерфейса — давайте лучше назовем ее TwoParamOperation — будет выглядеть примерно так:

public interface TwoParamOperation {
    BigDecimal compute(BigDecimal operand1, BigDecimal operand2);
}

Ваши фактические реализации часто могут быть:

public class Minus implements TwoParamOperation{
    @Override
    public BigDecimal compute(BigDecimal operand1, BigDecimal operand2) {
        return operand1.subtract(operand2);
    }
}

public class Pow implements TwoParamOperation{
    @Override
    public BigDecimal compute(BigDecimal operand1, BigDecimal operand2) {
        return operand1.pow(operand2.intValue());
    }
}

Затем вам нужно реализовать механизм выбора из этих стратегий. Вы можете просто иметь карту с именем операции в качестве ключа и экземпляром стратегии в качестве значения:

открытый класс Calc {

private Map<String,TwoParamOperation> operations = new HashMap<>();

public Calc(){
    add("MINUS", new Minus());
    add("POW", new Pow());
}

public void add(String opName,TwoParamOperation operation){
    operations.put(opName,operation);
}
    
    public Optional<BigDecimal> calculate(String opName, BigDecimal operand1, BigDecimal operand2){
    TwoParamOperation operation = operations.get(opName);
    if (operation!= null){
        return Optional.of(operation.compute(operand1,operand2));
    }
    return Optional.empty();
}

}

Таким образом, вы даже можете добавлять новые операции. Удаление зависит от вас.. Позвонив

Calc calc = new Calc();

BigDecimal x=calc.calculate("MINUS",BigDecimal.valueOf(2.3),BigDecimal.valueOf(42)).orElseThrow();

вы получаете результат для выбранной вами операции по двум параметрам, если такая операция реализована.

Если вам нужны операции с другими параметрами или типами результатов, вы можете добавить их как дополнительные карты других интерфейсов.

person juwil    schedule 19.01.2021