Design patterns, as their name implies, are models, paradigms, perspectives on how to solve certain recurring design problems. Strategy pattern is a design pattern that lets you use the same action with different executions to suit any desired situation. To start things off and give a more meaningful description to strategy pattern, let’s propose the following situation:
A store has its new system in place ready to start selling its product, but when a senior citizen approaches the counter, the cashier encounters a problem, there’s no way for her to calculate the adequate discount. Ten customers down the line, a veteran shows up, and the same discount problem arises. Finally, a minor wants to buy the product, and with the new law that approves minor discounts, the cashier decides to address this issue by contacting the developer on duty to fix the issue.
Since doing changes on the actual system is risky, you decide to do a console application first to have an idea on how to implement it later. The first idea that comes to mind is to build a simple class that has all the logic inside
but the structure makes it harder to implement a new behavior across all possible categories. Lets say the business wants to implement a points program where seniors get a certain percentage of the money spent per purchase, veterans another percentage and minors yet another. And for every new category, you’ll have to implement all the functions from scratch, lets say adding store employees for those benefits. With that in mind, the idea is discarded.
Having heard of the strategy pattern, you implement it.
First of all, the console application will have a random number to simulate a price. Then, the user will be asked to choose which discount to apply (the demo could be more complex and ask the customer for their age or their veteran ID card, but this is a fairly simple example). When the decision is made, it’ll be converted to a number and enter a switch statement to decide which discount to apply.
Here is where the strategy pattern starts. To separate the different groups, we’ll create a class for each, one for minors, one for veterans and one for senior citizens. As a base to what all groups shall be able to perform (in this case, get a discount), we’ll implement an interface which will define all functions and/or variables needed across all classes. The interface will serve the purpose of having a base idea or a template about what each class should implement to follow the strategy pattern and ensure these functions and/or variables are used in every class that will use the strategy pattern.
To create each individual class, an empty constructor is needed to instance the class when the discount is decided. Since all classes make use of the interface, they need the functions/variables that this interface has. In this example, it’s just the ‘calcDiscount’ function. The logic that makes each class unique should be applied in the over-writable functions, to make use of a single function that depends on the class being instanced.
Now that everything is in place, all we need is a way to store and reference the selected class. For that, we’ll create a context class. This context class will need an empty constructor to instance it initially. It will also need a variable of the same type as the interface to store all the necessary functions/variables the class uses. With that variable in place, we’ll create a function that will set that variable to the context we’ll be applying (that being applying the discount for minors, veterans or senior citizens). Lastly, another function that will invoke the function that is present in the context which contains the selected class for the calculations.
Coming back to the main program, we’ll need to instance the context class right before the switch, this is to have a context ready to be assigned the selected group. Inside each case scenario, we’ll be assigning the class to the context with the function created previously. With the context now using the correct class, we just need to call the function using the context and it will do the desired behavior.
To check that everything is in place, you write the results in the console and check that everything was correct. In the following example of the console running, the number was 391, the discount chosen was veterans, which apply a 10% discount, making the discount 39.1 and a final price of 351.9
Now that the strategy pattern is running perfectly in the demo, you’re ready to implement it in the store app.
To access the code, you can download it here (https://github.com/AnthonyWRodriguez/StrategyPattern)