flow.
"Flow is a condition of deep, nearly meditative involvement." - Tom DeMarco

Refactoring: Replacing Enums with the Strategy Pattern

Sunday, October 28, 2007 4:22 PM
Recently I came across some code in a framework that was performing different calculations on data as it was retrieved from data source.  The framework had a set of derived columns, each of which represented a set of predefined calculations against the retrieved data.  For example, we may have had a Sum column which was responsible for adding the values of two other columns together.  We also may have had a Difference column which was responsible for subtracting the value of one column from another column.  This is a pretty common, straight forward situation which I'm sure that nearly everyone has encountered at some point in their career.

Where this starts to break down is how the different calculations were implemented and specified.  Each calculation was represented by a CalculationMode enum which was passed to the Calculate() method along with the necessary parameters.  The Calculate() method contained a giant switch statement which checked the value of the CalculationMode enum, and depending on the value it found, performed the necessary calculation.  Makes sense, right?  Sure it does.  It makes sense, it works, and it's easy to implement.  To be honest, its probably how I would have implemented it at first, too. 

Here's a snapshot of some of our different CalculationModes available...

    /// <summary>
    /// Specifies the type of calculation to perform.
    /// </summary>
    public enum CalculationMode
    {
     . . . 
        /// <summary>
        /// Addition will be performed.
        /// </summary>
        Addition,
 
        /// <summary>
        /// Subtraction will be performed.
        /// </summary>
        Subtraction,

       . . .
    }


And here's the method that would use those enums

        /// <summary>
        /// Performs the calculation specified in mode on the values of op1 and op2 and
        /// then returns the results.
        /// </summary>
        /// <param name="op1">The first operand.</param>
        /// <param name="op2">The second operand.</param>
        /// <param name="mode">The mode of calculation to perform.</param>
        /// <returns>The result of the specified calculation.</returns>
        public double Calculate(double op1, double op2, CalculationMode mode)
        {
            double result;
            switch (mode)
            {
                case CalculationMode.Addition:
                    result = op1 + op2;
                    break;
                case CalculationMode.Subtraction:
                    result = op1 - op2;
                    break;
                . . .
                default:
                    throw new Exception("Unknown calculation type encountered.");
            }
            return result;
        }

Finally, this is how we would put this monster to use...

        /// <summary>
        /// The entry point.
        /// </summary>
        /// <param name="args">The args.</param>
        private static void Main(string[] args)
        {
            Calculation calculation = new Calculation();
            double result = calculation.Calculate(2, 4, CalculationMode.Addition);
            Console.WriteLine(result);
        }

The problem doesn't become evident until we try to maintain the code and extend it.  What happens when we need to add a new calculation mode 6 months from now...say 'Multiplication'.  Easy enough, we just go to the Enum method and add a value for Multiplication.  Then we just go to the Calculate function and add a case in the giant switch statement to handle Multiplication and implement the algorithm there.  Now, recompile.  What's that?  We want to be able to Divide, too?  Well, OK.  Let's go back to the switch statement, add a case for 'Division' and then implement the functionality there.  We're done!  Oops, no we're not.  We forgot to add a value back to the enums for Division.  Now we're done, right?  Nope, we have to recompile the system because we changed a core part of the codebase.  OK, so hopefully you've started to see that although this situation worked great to start with...it's definitely not ideal for a long term solution.  This is where the Strategy pattern comes in.

The Strategy pattern, according to Wikipedia, allows algorithms to be selected on-the-fly at runtime.  Algorithms on-the-fly at runtime...this sounds like exactly what we need.  How do we do this in C#?  Easy, we call on our old friend polymorphism.  Polymorphism allows us to specify different implementations of a different contract, or interface in this case, interchangeably.  To put it more in our context, we'll simply define an ICalculation interface with a single method Calculate().  This method will allow us to perform whatever calculation our implementor has specified without the consuming object knowing anything about it.  This means no monster switch statements, and no recompiling the entire codebase simply to add additional functionality.  And we also get the added benefit of abstracting some of our functionality out to interfaces which will help our unit testing out.  Here's what our code looks like after we've introduced the strategy pattern.

First, here's the interface that we define to abstract away the actual implementation of the Calculation method...

    /// <summary>
    /// Abstracts the implementing calculation from the consuming class.
    /// </summary>
    public interface ICalculation
    {
        /// <summary>
        /// Performs a calulation on the given values as operands.
        /// </summary>
        /// <param name="op1">The first operand.</param>
        /// <param name="op2">The second operand.</param>
        /// <returns>The result of the calculation.</returns>
        double Calculate(double op1, double op2);
    }

And here's a sample implementation of that interface...

    /// <summary>
    /// Performs addition.
    /// </summary>
    public class Addition : ICalculation
    {
        /// <summary>
        /// Adds the value of op1 to the value of op2 and returns the results.
        /// </summary>
        /// <param name="op1">The first operand.</param>
        /// <param name="op2">The second operand.</param>
        /// <returns>The result of the calculation.</returns>
        public double Calculate(double op1, double op2)
        {
            return (op1 + op2);
        }
    }

Here's how our new calculate method looks after we've stopped having to worry about the enum and the associated switch statement...

        /// <summary>
        /// Performs the calculation supplied in calculation on the values of op1 and op2
        /// and then returns the results.
        /// </summary>
        /// <param name="op1">The first operand.</param>
        /// <param name="op2">The second operand.</param>
        /// <param name="calculation">The implementation of the calculation to perform.</param>
        /// <returns>The result of the given calculation.</returns>
        public double Calculate2(double op1, double op2, ICalculation calculation)
        {
            return calculation.Calculate(op1, op2);
        }

A lot cleaner, huh?  Notice that not only is the switch statement gone, but we no longer have to even worry about what kind of calculation we're dealing with.  Whereas the previous implementation of Calculate() had to know not only all of the types of calculations available at compile time, it also had to know what to do with each of them.  Our new implementation completely delegates the actual functionality off to the  ICalculation implementation which means that it could have entirely new types of calculations added at runtime.  This portion of the code can be shipped and will never have to be touched again! 

Just to wrap things up, here's how you could use this new implementation...

        /// <summary>
        /// The entry point.
        /// </summary>
        /// <param name="args">The args.</param>
        private static void Main(string[] args)
        {
            Calculation calculation = new Calculation();
            double result = calculation.Calculate2(2, 4, new Addition());
            Console.WriteLine(result);
        }

I've include the source code for both implementations in one solution for download so that you can play around with both ideas.  Although enums aren't necessary a code smell for refactoring, they can definitely be a warning sign.  Especially if you find yourself having to make changes in more than one place, in this case both the enum and the corresponding switch statement, each time that you want to add new functionality.  If this sounds familiar to you, then it may be time to take a look at the strategy pattern for your own needs.

kick it on DotNetKicks.com

Feedback

 re: Refactoring: Replacing Enums with the Strategy Pattern

Thanks, this example case helped me a lot in understanding the Strategy Pattern! 10/29/2007 9:07 PM | Gabriel

# re: Refactoring: Replacing Enums with the Strategy Pattern

Of course strategy pattern is nice if you know when to use it. Most of the time though you are just substituting one swich statement for the other - you have to choose a strategy somewhere. 10/30/2007 4:36 AM | Michal Talaga

# re: Refactoring: Replacing Enums with the Strategy Pattern

Isn't that more like the Command pattern, or the Interpreter pattern?

Peace
-stephan 10/30/2007 5:24 AM | Stephan Schmidt

 re: Refactoring: Replacing Enums with the Strategy Pattern

Simple article but solution is not complete.
What about Calculations that require different parameter types? How would you solve this?
Generics? 10/30/2007 6:33 AM | liviu

 re: Refactoring: Replacing Enums with the Strategy Pattern

Very interesting.

A minor recommendation: Instead of using new Addition(), I would have a static Addition instance ready, and use it as: Addition.instance(). 10/30/2007 7:13 AM | Manx

 re: Refactoring: Replacing Enums with the Strategy Pattern

I prefer to use the CalculationMode enum but making it to implement the ICalculation interface.

public enum CalculationMode implements ICalculation {
. . .
Addition {
public double Calculate(double op1, double op2) {
return (op1 + op2);
}
},
...
}

Thus, I can to use enums and make the framework extensible using interfaces. 10/30/2007 8:05 AM | Jonhnny Weslley

# re: Refactoring: Replacing Enums with the Strategy Pattern

Excellent use of refactoring, but how do you determine which calculation instance to instatiate? That is, how do you know if it's a new Addition() or a new Subtraction(), etc.? 10/30/2007 9:37 AM | Mitchell Land

# re: Refactoring: Replacing Enums with the Strategy Pattern

This is not about pattern but more about conception of using Strategy pattern instead of switch statement. Big switch statement described by Martin Fowler as a "Code Smell" and Strategy or State patterns are the way how to refactor the code and make it easy maintainable.

Refactoring: Improving the Design of Existing Code by Martin Fowler http://martinfowler.com/books.html 10/30/2007 10:01 AM | Armen Ayvazyan

# re: Refactoring: Replacing Enums with the Strategy Pattern

In the summer I posted about using enum for strategy and related patterns: http://binkley.blogspot.com/2007/07/more-with-java-enums-simulating.html
10/30/2007 10:14 AM | B. K. Oxley (binkley)

 re: Refactoring: Replacing Enums with the Strategy Pattern

I understand it... But I can't say that I like it.

Instead of adding an enum entry, and a case to the switch, you force the programmer to write a whole 'nother class that implements your interface.

As far as readability goes, I'd rather pass an enumeration to a method than an instantiation. It is absolutely clear (and less clever) what you are requesting from that method. 10/30/2007 10:55 AM | KnuthCheck

# re: Refactoring: Replacing Enums with the Strategy Pattern

Maybe this example is not the best one for Strategy because we could use good old OOP approach without any class explosion risks etc
Simple OOP receipt:
- defining abstract Calculation class with
abstract double Calculate(double op1, double op2);
- Implement abstract member in AdditionCalculation class
- Use polymorphism...
I think good example for strategy should include a class where "auxiliary" behavior is implemented using strategy.
When the strategy is used on single main behavior it becomes maybe overkill (like in this example)...
10/30/2007 3:45 PM | Nikola Malovic

# re: Refactoring: Replacing Enums with the Strategy Pattern

Mitchell: We know which object to create, because that would be the operation we happen to need performed at that particular time. That is in end-user code, not library code.

Also, that way we'd really want to handle this is
would be to replace the enum with a class called CalculationMode defined basically like this:
public class CalculationMode
{
class AdditionOp : ICalculation
{
public double Calculate(double op1, double op2)
{
return op1 + op2;
}
}

class SubtractionOp : ICalculation
{
public double Calculate(double op1, double op2)
{
return op1 - op2;
}
}


static public ICalculation Addition
{ get { return new AdditionOp(); } }


static public ICalculation Subtraction
{ get { return new SubtractionOp(); } }
}

That way, the original user code does not need to change at all.
Calculation calculation = new Calculation();
double result = calculation.Calculate(2, 4, CalculationMode.Addition);
Console.WriteLine(result);

I think this was what Jonhnny was getting at, although I don't think what he wrote will compile (not in .Net at least) 10/31/2007 10:56 AM | James Curran

# re: Refactoring: Replacing Enums with the Strategy Pattern

Nice read. I like how you walked through all the steps to get to your conclusion. You have good insightful commenters on here too. :) 11/16/2007 5:55 AM | Luc

# re: Refactoring: Replacing Enums with the Strategy Pattern

Luc,

Glad you enjoyed it, thank you for the kind compliment. And you're completely correct about the commenters, I typically learn more from the people who are kind enough to comment on this blog than I do from any other source.

Jeremy 11/16/2007 9:41 AM | Jeremy

 re: Refactoring: Replacing Enums with the Strategy Pattern

So, what is the benefit of passing the object and the operands to the calculate method rather than passing the result of the calculation?
Maybe the example is so oversimplified that it is missleading me, but I don't clearly see the point. 11/23/2007 1:25 PM | bastian

 re: Refactoring: Replacing Enums with the Strategy Pattern

How about implementing the strategy pattern within the enum itself? Then there's no need for the switch statement and you can call the calculate method on the enum object itself.

public enum CalculationMode {
ADDITION {
public double calculate(double op1, double op2) {
return op1 + op2;
}
},

SUBTRACTION {
public double calculate(double op1, double op2) {
return op1 - op2;
}
};

public abstract double calculate(double op1, double op2);

} 2/7/2009 11:15 AM | Alex

# re: Refactoring: Replacing Enums with the Strategy Pattern

Hi Alex,

Thanks for the comment. That's actually very (I didn't realize you could do that!) but I can't get it to work. Can you post a complete example? I'd love to learn how to do this.

Thanks!
Jeremy 2/8/2009 2:04 PM | Jeremy

Post a comment





 

Please add 2 and 4 and type the answer here: