Apply discount changes with Strategy pattern

Posted on

Problem

I am implementing strategy pattern. I have defined a strategy as interfaces and concrete classes to implement the strategy. Based on user selection/configuration, the algorithm to apply the discount changes.

  public interface IStrategy
    {
        double calculate(double x, double y);
    }

concrete classes implementing the gold strategy is listed below –

public class clsGoldDiscountStrategy : IStrategy
    {
        public double calculate(double x, double y)
        {
            return (x * y) * 0.8;
        }
    }
}

concrete classes implementing the platinumstrategy is listed below –

public class clsPlatinumDiscountStrategy : IStrategy
    {
        public double calculate(double x, double y)
        {
            return (x * y) * 0.7;
        }
    }

The business logic to apply

public class clsBL
    {
        public double costPrice { get; set; }
        public double qty { get; set; }
        IStrategy _strategy;

        public clsBL(IStrategy strategy)
        {
            _strategy = strategy;
        }

        public double GetfinalPrice(double cp, double qty)
        {
            return _strategy.calculate(cp, qty); 
        }

    }

//Main method

static void Main(string[] args)
        {
            Console.WriteLine("Enter the discount Plan (Gold/Platinum)");
            string filter = Console.ReadLine().ToUpper();
            double result = 0;

            if (filter.Length > 0)
            {
                switch (filter)
                {
                    case "GOLD":
                        //Gold 
                        clsBL blgold = new clsBL(new clsGoldDiscountStrategy());
                        blgold.costPrice = 5;
                        blgold.qty = 10;

                        result = blgold.GetfinalPrice(blgold.costPrice, blgold.qty);
                        break;

                    case "PLATINUM":
                        //Platinum
                        clsBL blplatinum = new clsBL(new clsPlatinumDiscountStrategy());
                        blplatinum.costPrice = 10;
                        blplatinum.qty = 8;

                        result = blplatinum.GetfinalPrice(blplatinum.costPrice, blplatinum.qty);
                        break;
                    default:
                        Console.WriteLine("Enter the discount value as either  gold or platinum");
                        break;
                }

                Console.WriteLine("The result for " + filter + " is " + result);

            }
            else
            {
                Console.WriteLine("Enter the discount value");
                return;
            }


            Console.ReadLine();

        }

Solution

The classes seem OK but the usage makes no sense:

                case "GOLD":
                    //Gold 
                    clsBL blgold = new clsBL(new clsGoldDiscountStrategy());
                    blgold.costPrice = 5;
                    blgold.qty = 10;

                    result = blgold.GetfinalPrice(blgold.costPrice, blgold.qty);
                    break;

This code (and the other switch case) does not use the polymorphism that the interface IStrategy enables. Rather, you can have simply written this code as:

                case "GOLD":
                    double GetGoldPrice(double x, double y) => (x * y) * 0.8;
                    result = GetGoldPrice(5, 10);
                    break;

Here, all classes and interfaces are deleted. There is just a static method.

If you want to use the strategy pattern it must look something like:

IStrategy strategy = GetStrategy();
strategy.Calculate(...);

Here, GetStrategy() can return any object compliant with that interface and further code does depend on any concrete type.


Regarding naming, the classes do not have to be called “Strategy”. I’d use the names IDiscountCalculator and GoldDicountCalculator. Or, instead of “Calculator” you could use “Model” or “Provider”.

x and y are really bad parameter names. I had to look at the client code to figure out that these were actually cost and quantity.

public double costPrice { get; set; }
public double qty { get; set; }

There is no point of having these two properties if you are passing those values to GetfinalPrice anyway:

public double GetfinalPrice(double cp, double qty)
{
    return _strategy.calculate(cp, qty); 
}

Pick one, otherwise it’s pretty confusing.

Leave a Reply

Your email address will not be published. Required fields are marked *