When writing code, there are often multiple ways to achieve the same functionality. At first glance, it might seem logical to pick the easiest or quickest implementation. But great software development isn’t just about solving the problem at hand — it’s about anticipating the future.
Ask yourself:
Will my code be easy to extend when new requirements arise?
Is my code maintainable and self-explanatory for others (or even my future self)?
Does my code ensure optimal application performance?
This is where design principles and patterns come into play. They provide a roadmap for writing scalable, maintainable, and efficient code. SOLID principles underpin these best practices, while design patterns provide proven structures for solving everyday problems.
In this article, we’ll explore the Strategy pattern, a design pattern rooted in SOLID principles, and see how it helps us write clean, flexible, and future-proof code.
Now it is time to dive into the Strategy pattern. Let’s understand it with the following scenario.
Assume you are building a Military/war video game with different characters such as Soldiers, Knights, Archers, Giants, and builders. Each character is displayed differently in our game environment, and we use the Display() method to display each character. All the above characters can fight except the Builders. Builders can only build castles, monuments, and other buildings.
Soldiers and knights fight with swords,
Archers fight with their Archery.
Giants fight with their Hands.
Builders cannot fight.
Characters can fight according to the Fight() method.
How would you implement this?
You will create a super class as a Character and create each of these other characters as sub classes of it. Then you would create an abstract method as Display() . so you can implement the function in each character class. To handle each character fighting you will create a Fight() method in super-class. Only for Builder you will override the Fight() method to Do Nothing .
All these characters can move and they move by walking. So you will have to create a function as Move() in the super-class and return ‘Move by Foot’.
public class Character {
public abstract void Dispay();
public void Move(){
Console.WriteLine("Move by Foot");
}
public void Fight() {
Console.WriteLine("Fight by Sword");
}
}
public class Soldier extends Character{
public void Display() {
Console.WriteLine ("Display Soldier");
}
}
public class Builder extends Character {
public void Display() {
Console.WriteLine ("Display Builder");
}
// override Fight method
public override void Fight(){
Console.WriteLine("Cannot Fight");
}
// other subclasses goes here
}Do You think the above implementation is a good one?
What if we want to add a new character as a King, where he also cannot fight? Then we have to override the king’s Fight() method to do nothing. If we add more characters such as Blacksmiths, Healers, etc. who cannot participate in combat and fight, then we will have to override the Fight() method on multiple occasions and repeat same code. This leads to code duplication and violates the DRY (Don’t Repeat Yourself) principle.
Furthermore, consider a new character like a cavalry who can fight but moves by riding a Horse. This scenario would require overriding the Move() method for the cavalry class, introducing potential complexities in the inheritance hierarchy.
These challenges highlight the limitations of the current approach. The need to repeatedly override methods to handle specific cases and the potential for complex inheritance structures can significantly reduce code maintainability and increase the risk of introducing errors. Therefore we need find another method to handle these complex relationships.
Solution for inheritance is not more inheritance.
Introduce Strategy pattern
In Strategy pattern, we define strategies (or behaviors) and try to handle the scenario using composition rather than inheritance.
There is a design principle that says Favor composition over inheritanceI defined an interface as IFightBehavior and then created concrete sub-classes for each fighting method as FightWithHands, FightWithSwords, and FightWithArchery.
Next, I created another interface to handle movement behaviors as IMoveBehaviors, and defined sub-classes as MoveByFoot, and MoveByHorse. Concrete characters like Soldier, Knight, Builder and cavalry get their Fight and move behaviors not by inheritance, but by composing with right object of concrete implementation of behavior classes. This approach promotes flexibility and allows characters to dynamically change their behaviors at runtime.

Join the conversation! Your thoughts help the community grow.