Wednesday, July 25, 2007

Strategy pattern : Algorithm on the Fly

hi,
i am back with another pattern. Today we will discuss about "Strategy Pattern".

consider this scenario : i want to develop a game which has soldiers fighting.
right now i have only one soldier "SharpShooter". but i would like to enhance the game by including some more soldier types. how we go about the design?
well the first thing which we all think of is reuse. so we develop a single class called "Soldier", then we extend ( inherit) this class in other classes.

the code for this will be

public class Soldier
{
public Soldier()
{
}

public virtual void FightEnemy()
{
MessageBox.Show("I am fighting");
}
}

the FightEnemy is a simple function in this case, but i plan to add functionality here once i find out what the game character has to do.

now i have the SharpShooter Class which will extend Soldier

public class SharpShooter : Soldier
{
public SharpShooter()
{
}
public override void FightEnemy()
{
MessageBox.Show("I am shooting Bullets");
}
}

but the disadvantage with this problem is the method has to be overridden in the derived classes.
why? i will tell you the answer

consider an unconscious soldier who will never be able to fight,the class will be:

public class UnconsciousSoldier : Soldier
{
public UnconsciousSoldier()
{
}

}

but when you call :

Soldier s = new UnconsciousSoldier();
s.FightEnemy();

the soldier starts fighting and the message box "I am fighting" pops up.
so we have to make sure that we override the FightEnemy() in all the derived classes of Soldier.
but don't you think this is a little too much?
if i forget overriding, then the soldier, even if dead, starts fighting ( i don't want lord of the rings here where we have UnDead) .

but i have a much more easy to use solution:

we apply the design principle :
"separate whatever varies and encapsulate them"
here the fighting behavior varies.

we will take the fighting behaviors and then separate them from the class.
for this we will have an interface called IFightBehaviour :

interface IFightBehaviour
{
void Fight();
}

now we apply another design principle
"Program to an interface not to an implementation".

So we will have the soldier as an interface, not as a class :

interface ISoldier
{
void FightEnemy();
}


we will introduce new fighting behaviors now. how do we do it?
we just implement the IFightBehavior interface :

class SharpShoot : IFightBehaviour
{
#region IFightBehaviour Members

void IFightBehaviour.Fight()
{
MessageBox.Show("Shooting Bullets");
}

#endregion
}


class DeadSoldierBehavior : IFightBehaviour
{
#region IFightBehaviour Members

void IFightBehaviour.Fight()
{
MessageBox.Show("Cannot fight,so do nothing");
}

#endregion
}



now we will apply another design principle :
"Has a is better than is a". what does this mean? "composition is better than inheritance".
so the fightbehaviour will be a part of the Soldier classes :

class SharpShooter : ISoldier
{
IFightBehaviour FightBehaviour;


public SharpShooter(IFightBehaviour pFightBehaviour)
{
FightBehaviour = pFightBehaviour;
}
public void FightEnemy()
{
FightBehaviour.Fight();
}
}


now IFightBehaviour is a part of SharpShooter class.

now we instantiate SharpShooter like this :

IFightBehaviour FightBehaviour = new SharpShoot();
SharpShooter shooter = new SharpShooter(FightBehaviour );
shooter.FightEnemy();

now in case of dead Soldiers, we will have need not have another class,
we can modify the same class with a new fightbehaviour. how is this? i will explain

consider the code given below

IFightBehaviour FightBehaviour = new DeadSoldierBehavior ();
SharpShooter shooter = new SharpShooter(FightBehaviour );
shooter.FightEnemy();

(DeadSoldierBehavior is a class implementing IFightBehavior which denotes what a dead soldier has to do)
the above code snippet will print
"Cannot fight,so do nothing",which was coded in the FightEnemy() function of "DeadSoldierBehavior " class.

so we can change the behaviour of the the class at runtime. How?

simple, consider the snippet below :

IFightBehavior FightBehavior;
//if soldier is alive and is a shooter

FightBehavior = new SharpShoot();
SharpShooter shooter = new SharpShooter(FightBehaviour );
shooter.FightEnemy();

//elseif the soldier is dead

FightBehavior = new DeadSoldierBehavior ();
SharpShooter shooter = new SharpShooter(FightBehaviour );
shooter.FightEnemy();



i want to add a new behavior like- say a demolition specialist, all i need to do is create a new Fightbehavior class implement IFightBehavior in this class and implement Fight() function to suit a demolition expert.
and the rest is all the same: create an instacne of demolitionFightbehavior class and apss it as a parameter to SharpShooter class and call the FightEnemy().

when do we need to use Strategy pattern?
when we want to change behaviors on the fly (at runtime).
or
when we want different algorithms to be executed at the fly.

we could have done it using several if else, switch case etc.
but just how managable and maintainable would that be?
and the most important of all would it be flexible? no not at all.
just look at the code which we have now?
we have just a few classes but look how flexible the design is.
we can add a new functionality with less modifications to the existing classes.
we strictly follow the "open close" principle here :
A design should be open for extension but closed for modification.

this is the strategy pattern.

happy coding !!!

regards,
nandan

No comments: