I recently downloaded a cool fighter plane game (iFighter lite) on my iPhone. As I started playing, I felt that plane is moving a bit slow!! But soon enough I saw a little perk on the screen and I flew over it and suddenly plane's speed increased. Soon enough, enemy planes started attacking me and I shot back at them. But again I felt my bullets were too slow! I shot down few planes and a new perk showed up on the screen. As soon as I collected it, my plane started shooting more bullets per attack!!
Yeeee hoo!!! I started enjoying this and before I knew, I by mistake collected a "skull and bones" perk and "darrnn!!" I said, cause I knew now my plane had lost those powerful bullets :(
Now, of course I am not writing a review about the human behavior while playing games on iPhone! But what I am trying to highlight here is the plane's ability to act differently in certain conditions! And that's something the Strategy Design Pattern allows us to do. I’ll try to use this game as an analogy to discuss about Strategy Design Pattern.
Definition: Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
So if you think about it, the game engine has defined the family of algorithms and (ability to shoot bullets, ability to fly with different Speeds etc) uses them interchangeably which allows the plane to shoot bullets from less to more per attack and fly with less speed to increased speed and vice versa.
Lets put this little “game”, into a bit more technical paradigm. So here we are talking about some objects and their behaviors. We are talking about planes and their flying and shooting behaviors. We have two kinds of planes here, our plane and enemy planes. We know that all planes can fly, can turn left, can turn right regardless if it’s our plane or enemy planes. So there should be an abstract base class called Plane, which implements these obvious behaviors by itself (concrete methods).
We know that each type of plane has to distinguish itself through a unique outer display. So each plane have to take care of their own display or body work and hence, the Plane class leaves the implementation of the display() method to the concrete classes. Like we have My Plane and Enemy Plane classes here.
Because the flying behavior is variable for planes, we have pulled it out from the Plane class and encapsulated it separately. We did the same with the attack behavior. In fact that’s one of the rules while applying any design patterns to your existing design, which says “Identify the aspects of your application that vary and separate them from what stays the same.” So we identified, flying and shooting behaviors vary in our case. There is one more rule I would like to mention here. “Program to Interface not to the implementation”. This allows the design to be much more dynamic and scalable in the future.
Pay attention to methods setFlyBehavior() and setAttackBehavior(), they expect iFlyBehavior and iAttackBehavior respectively. These are the methods which actually turns this whole design into a dynamic design. Client code is able to call these methods and change the behaviors from FlySlow to FlyFaster!!
Now what next!? Well, now it’s the time for our little simulation of this iPhone game through C#.
And here’s the main() method that runs this code. As you can see, setFlyBehavior() method causes it to change the speed to 300 km/hour and shooting frequency also gets increased on the fly!
static void Main(string args)
Plane plane = new MyPlane();
Console.WriteLine("My Plane, Start Flying....");
Console.WriteLine("My Plane, Start Shooting....");
Console.WriteLine("****** My Plane collected an 'Increase Speed' item on screen ********");
Console.WriteLine("****** My Plane collected an 'Increase Attack Speed' item on screen ********");
In future if they want to add few more flying behaviors or attacking behaviors, they can simply create new concrete classes for those behaviors and they are done. They don’t need to change the Plane class. They even can add a whole new kind of plane which is a type of Bomber. In fact, in the game, at one stage, you can call upon a Bomber which takes care of all the enemy tanks on the ground in one shot. This Bomber is of course derived from Plane class but it has its own way of dealing with the Bad Guys!!
Apart from this demo, I actually used Strategy Pattern in my code too. I didn’t mention it in detail like iFighter’s demo. Because main purpose of this article is to uncover the awesome powers of Strategy Pattern and it would be easier to demonstrate with a simpler example like this.
Problem that I solved using Strategy Pattern
In our system, we have to send out the email notifications to number of recipients depending on the type of the event happened. Generally, it's just a static email message, saying something has happened in the system. But in my case, this email body will be generated dynamically. There is some static text and along with it, I also have place holders (Tags) for the data which will be pulled from the data source when the email notification is ready to be sent out. So for each event type, it has its own message format and each message format has its own Tags.
Following image will provide a little more details about the tags and the formats.
So as you can see above, the event HR Days Off Requested actually generates two notifications, one to employee and other to the Supervisor. They both have the similar data but the formats of the email bodies are different. We can identify this “variability” with the different flying / attacking behavior of the plane.
Here, the getNotificationData() method is where all the action happens. HRDaysOffRequestEmployeeFormat and HRDaysOffRequestSupervisorFormat implements this method separately, just like in iFighter example, FlySlow and FlyFast classes implemented fly() method individually. I know it’s not really a BIG deal here and it sounds like overkill to use the pattern for this problem. But hey, I did want to see it in action for REAL!! ;)
Here are some more facts about the Strategy Design Patter and probably the reasons why you should think about using it some day!
Strategy pattern uses composition instead of inheritance. In the strategy pattern behaviors are defined as separate interfaces and specific classes that implement these interfaces. Specific classes encapsulate these interfaces. This allows better decoupling between the behavior and the class that uses the behavior. The behavior can be changed without breaking the classes that use it, and the classes can switch between behaviors by changing the specific implementation used without requiring any significant code changes. Behaviors can also be changed at run-time as well as at design-time.
Plane Demo Source code: