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.