0

There is creating each possible strategy in Main function in any strategy pattern example, for example:

Context cn = new Context(new CQuickSorter());
cn.Sort(myList);

cn = new Context(new CMergeSort());
cn.Sort(myList);

But in some place we have to choose what strategy we should use, where we should place 'switch' to choose a correct strategy? In a method? I saw class with method with 'switch' which returned OBJECT - the correct strategy class instance but then that is factory, not strategy pattern.

Where should be 'switch' in strategy pattern without factory? I have that in method like below - is it ok?

enum Operation
{
    Addition,
    Subtraction
}

public interface IMathOperation
{
    double PerformOperation(double A, double B);
}

class AddOperation : IMathOperation
{
    public double PerformOperation(double A, double B)
    {
        return A + B;
    }
}

class SubtractOperation : IMathOperation
{
    public double PerformOperation(double A, double B)
    {
        return A - B;
    }
}

class CalculateClientContext
{
    private IMathOperation _operation;

    public CalculateClientContext(IMathOperation operation)
    {
        _operation = operation;
    }

    public double Calculate(int value1, int value2)
    {
        return _operation.PerformOperation(value1, value2);
    }
}

class Service
{
    //In this method I have switch
    public double Calculate(Operation operation, int x, int y)
    {
        IMathOperation mathOperation = null;

        switch (operation)
        {
            case Operation.Addition:
                mathOperation = new AddOperation();
                break;
            case Operation.Subtraction:
                mathOperation = new SubtractOperation();
                break;
            default:
                throw new ArgumentException();
        }

        CalculateClientContext client = new CalculateClientContext(mathOperation);
        return client.Calculate(x, y);
    }
}
  • Who said a factory can´t provide a stategy? – MakePeaceGreatAgain Feb 19 '19 at 10:26
  • So there is no purpose to use only pure strategy because factory with strategy is much more elegant. – Aleksander Chelpski Feb 19 '19 at 10:38
  • If a factory should be avoided, then a solution would be to (1) add on the strategies a method signalling which operation the strategy supports (2) have a collection with all strategies (3) where the strategy needs to be used iterate over the strategies collection and find the strategy which supports the operation and use it –  Feb 19 '19 at 10:52
  • It´s not the question which of them fits better, as both serve different purposes. While the concrete strategy defines "how to do things", the factory defines "which strategy to use". However you won´t need a factory to create a strategy. – MakePeaceGreatAgain Feb 19 '19 at 11:26
  • 1
    Having said this there´s no general solution which pattern to use and how to do so. – MakePeaceGreatAgain Feb 19 '19 at 11:31

2 Answers2

1

The most flexible approach is to delay the decision ("switch") for as long as possible. For example, if you start with something like this:

Context cn = new Context(); // Don't care about the sorter yet...
cn.Sort(new CQuickSorter(), myList); // OK, NOW the sorter is needed, let's inject it now.

You can make the decision at any point prior to calling object.Sort(). The decision can be implemented in a simple if-else block, or in a complex factory. At the end of the day, the best implementation is going to depend on the complexity of your project. Hence, there's no hard rule defining where you should place the switch.

As an exercise, you can apply the various creation patterns to see how they play out. That will help you get a sense of when to use each design pattern.

Emmanuel Rosa
  • 9,697
  • 2
  • 14
  • 20
0

When applying dependency injection, domain objects should be instantiated and wired together (i.e. have their dependencies, such as strategies, provided) within the composition root. In modern, practical terms, this means your DI container instantiates and provides a strategy to a context (client) object, based on configuration. There is no switch.

jaco0646
  • 15,303
  • 7
  • 59
  • 83