Click here to Skip to main content
15,892,737 members
Home / Discussions / C#
   

C#

 
AnswerRe: general query related to C# Pin
V.4-Dec-14 20:03
professionalV.4-Dec-14 20:03 
GeneralRe: general query related to C# Pin
den2k885-Dec-14 0:35
professionalden2k885-Dec-14 0:35 
GeneralRe: general query related to C# Pin
Member 112872605-Dec-14 2:44
Member 112872605-Dec-14 2:44 
GeneralRe: general query related to C# Pin
V.5-Dec-14 2:46
professionalV.5-Dec-14 2:46 
GeneralRe: general query related to C# Pin
Member 112872605-Dec-14 3:02
Member 112872605-Dec-14 3:02 
GeneralRe: general query related to C# Pin
Member 112872605-Dec-14 3:39
Member 112872605-Dec-14 3:39 
GeneralRe: general query related to C# Pin
V.5-Dec-14 4:36
professionalV.5-Dec-14 4:36 
QuestionQuestions about refactoring switch statement to Strategy Pattern in C# Pin
Member 97402194-Dec-14 11:48
Member 97402194-Dec-14 11:48 
There are many situations where an object has to be able to change its calculation based on a user input. Examples are applying discounts to an order, calculating shipping charges, and so many more. There are also many examples on the web that show if you implemented this logic using an enum, a switch statement and private methods, you should refactor the code using the strategy pattern. I don’t have an issue with understanding how to refactor the code. At the bottom of this post I have included sample code that shows the before and after refactored code.

However, I have found myself asking three questions after reading these posts and I am hoping that some one can explain it to me.

1. Suppose these calculations really will only apply to this object. Why do I want to make them more accessible by putting them in their own class that at a minimum is accessible to the entire assembly?

2. In the examples on the web; there is a class that calls the context object. The code below is typical of what you will find in posts. It creates the context object for each calculation method. I know it serves to show you the different results, however, I believe it hides an issue.

C#
// Class that starts the calculation process - Sample Code seen on the web
        public class ClassThatCallsContextObject
        {
            public void StartCalculation ( )
            {
                decimal calculationResult = 0.0M;

                ContextObject contextObject;

                // Initilize the contextObject with the first calculation method
                contextObject = new ContextObject(new CalculationMethod1());
                calculationResult = contextObject.Calculation();
                // calculationResult would be set to 1.0

                // Initilize the contextObject with the second calculation method
                contextObject = new ContextObject(new CalculationMethod2());
                calculationResult = contextObject.Calculation();
                // calculationResult would be set to 2.0
            }
        }


In an actual application, only one of the choices will be selected. This selection can be made by the user, by a business rule, read in from the database, etc. That selection requires different code. I think you need to add back the enum and the switch statement to implement this code. Below is an example of the code.

C#
// Define the possible calculation strategies
    public enum CalculationStrategies { Method1, Method2}

// Class that starts the calculation process - With User Selection
    public class ClassThatCallsContextObjectWithUserSelection
    {
        public void StartCalculation ( CalculationStrategies userInput )
        {
            decimal calculationResult = 0.0M;

            ContextObject contextObject;

            switch (userInput)
            {
                case CalculationStrategies.Method1:
                    // Initilize the contextObject with the first calculation method
                    contextObject = new ContextObject(new CalculationMethod1());
                    calculationResult = contextObject.Calculation();
                    // calculationResult would be set to 1.0
                    break;
                case CalculationStrategies.Method2:
                    // Initilize the contextObject with the second calculation method
                    contextObject = new ContextObject(new CalculationMethod2());
                    calculationResult = contextObject.Calculation();
                    // calculationResult would be set to 2.0
                    break;
            }
        }
    }


Is there a better way to implement this selection code?

3. Assuming item 2 is the best way to do this, when the time comes to add a new calculation (and we all know that it will be here eventually), the following work has to be done:

A. Add the new calculation to the enum.
B. Add a new switch statement to the object that calls the context object.
C. Create a new class that implements the new calculation.

If I didn't refactor the code, here is the work I would need to do.

A. Add the new calculation to the enum.
B. Add a new switch statement to the context object.
C. Create a new private method that implements the new calculation.

This looks like pretty much the same thing. So, what is the advantage of the refactored code?

Complete code examples for reference:

Switch Statement Code

C#
// Class that starts the calculation process
    public class ClassThatCallsContextObject
    {
        public void StartCalculation ()
        {
            decimal calculationResult = 0.0M;

            ContextObject contextObject = new ContextObject();
            calculationResult = contextObject.Calculation(CalculationStrategies.Method1);
            // calculationResult would be set to 1.0
            calculationResult = contextObject.Calculation(CalculationStrategies.Method2);
            // calculationResult would be set to 2.0
        }
    }

    // Define the possible calculation strategies
    public enum CalculationStrategies { Method1, Method2}

    // Class that executes the calculations
    public class ContextObject
    {
        // Constructor
        public ContextObject ()
        {

        }

        // Method that has multiple ways to calculate the value depending on user input
        public decimal Calculation ( CalculationStrategies selectedStrategy )
        {
            decimal calcualtedValue = 0.0M;
            switch (selectedStrategy)
            {
                case CalculationStrategies.Method1:
                    calcualtedValue = CalculationMethod1();
                    break;
                case CalculationStrategies.Method2:
                    calcualtedValue = CalculationMethod2();
                    break;
            }
            return calcualtedValue;
        }

        // Calculation Method 1
        private decimal CalculationMethod1 (  )
        {
            return 1.0M;
        }

        // Calculation Method 2
        private decimal CalculationMethod2 ()
        {
            return 2.0M;
        }
    }


Strategy Pattern Code

C#
// Class that starts the calculation process - Sample Code seen on the web
        public class ClassThatCallsContextObject
        {
            public void StartCalculation ( )
            {
                decimal calculationResult = 0.0M;

                ContextObject contextObject;

                // Initilize the contextObject with the first calculation method
                contextObject = new ContextObject(new CalculationMethod1());
                calculationResult = contextObject.Calculation();
                // calculationResult would be set to 1.0

                // Initilize the contextObject with the second calculation method
                contextObject = new ContextObject(new CalculationMethod2());
                calculationResult = contextObject.Calculation();
                // calculationResult would be set to 2.0
            }
        }

        // Define the possible calculation strategies
        public enum CalculationStrategies { Method1, Method2 }

        // Class that executes the calculations
        public class ContextObject
        {
            private ICalculationMethod _calculationMethod;

            // Constructor
            public ContextObject ( ICalculationMethod calculationMethod )
            {
                _calculationMethod = calculationMethod;
            }

            // Method that has multiple ways to calculate the value depending on user input
            public decimal Calculation ()
            {
                return _calculationMethod.CalculationMethod();
            }
        }

        interface ICalculationMethod
        {
            decimal CalculationMethod ();
        }

        public class CalculationMethod1 : ICalculationMethod
        {
            // Calculation Method 1
            private decimal CalculationMethod ()
            {
                return 1.0M;
            }
        }

        public class CalculationMethod2 : ICalculationMethod
        {
            // Calculation Method 2
            private decimal CalculationMethod ()
            {
                return 2.0M;
            }
        }

AnswerRe: Questions about refactoring switch statement to Strategy Pattern in C# Pin
SledgeHammer014-Dec-14 12:24
SledgeHammer014-Dec-14 12:24 
GeneralRe: Questions about refactoring switch statement to Strategy Pattern in C# Pin
BillWoodruff4-Dec-14 18:36
professionalBillWoodruff4-Dec-14 18:36 
GeneralRe: Questions about refactoring switch statement to Strategy Pattern in C# Pin
Matt T Heffron5-Dec-14 6:51
professionalMatt T Heffron5-Dec-14 6:51 
Questionpostback issue with dynamically created datetimepicker Pin
Dhyanga4-Dec-14 4:58
Dhyanga4-Dec-14 4:58 
SuggestionRe: postback issue with dynamically created datetimepicker using javascript Pin
Richard MacCutchan4-Dec-14 5:01
mveRichard MacCutchan4-Dec-14 5:01 
GeneralRe: postback issue with dynamically created datetimepicker using javascript Pin
Dhyanga4-Dec-14 8:04
Dhyanga4-Dec-14 8:04 
QuestionHow to find a particular embedded resource in an assembly? Pin
Sivaji15654-Dec-14 1:08
Sivaji15654-Dec-14 1:08 
SuggestionRe: How to find a particular embedded resource in an assembly? Pin
Richard MacCutchan4-Dec-14 2:06
mveRichard MacCutchan4-Dec-14 2:06 
QuestionC# Error check Pin
Member 112847343-Dec-14 18:06
Member 112847343-Dec-14 18:06 
AnswerRe: C# Error check Pin
Manfred Rudolf Bihy3-Dec-14 18:20
professionalManfred Rudolf Bihy3-Dec-14 18:20 
GeneralRe: C# Error check Pin
Member 112847343-Dec-14 18:34
Member 112847343-Dec-14 18:34 
GeneralRe: C# Error check Pin
Manfred Rudolf Bihy3-Dec-14 19:53
professionalManfred Rudolf Bihy3-Dec-14 19:53 
AnswerRe: C# Error check Pin
Harsh Athalye5-Dec-14 0:14
Harsh Athalye5-Dec-14 0:14 
QuestionHow to copy a file from my computer to a shared folder of another computer with login username and password account Pin
Derz3-Dec-14 14:58
Derz3-Dec-14 14:58 
AnswerRe: How to copy a file from my computer to a shared folder of another computer with login username and password account Pin
PIEBALDconsult3-Dec-14 16:23
mvePIEBALDconsult3-Dec-14 16:23 
Questioninvalid length for a base-64 char array or string Pin
Jassim Rahma3-Dec-14 11:35
Jassim Rahma3-Dec-14 11:35 
SuggestionRe: invalid length for a base-64 char array or string Pin
Richard MacCutchan3-Dec-14 20:56
mveRichard MacCutchan3-Dec-14 20:56 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.