Strategy
The Strategy design pattern allows you to use multiple algorithms interchangeably.
One reason you might use a Strategy Pattern is to simplify an overly complex algorithm. Sometimes, as an algorithm evolves to handle more and more situations, it can become very complex and difficult to maintain. Breaking these complex algorithms down into smaller more manageable algorithms might make your code more readable and more easily maintained. As a simple example of how to implement the Strategy Pattern consider the following scenario.
A software system uses a single authorization checking class to determine access rights within the system. Access rights will be different for Anonymous users, Logged-In users and System Administrators.
While we could certainly handle these 3 different access levels within a single class, but what if a fourth type of access level were to be added and perhaps a fifth? Let's break out each of the access checks into its own Strategy object that we can use interchangeably based on what type of user is logged into our system.
First, we need to define an Interface that all of our Strategy classes will implement. It is by implementing this Interface that our Strategy classes will be able to be used interchangeably.
Public Interface IAuthorityCheck
Function IsAuthorized(ByVal resource As Object) As Boolean
End Interface
With a simple interface defined, we can now create any number of different classes that will implement that interface and perform our security checks for us. Here are 3 examples that represent our Strategy classes.
First, for our Anonymous users, we create a security Strategy class that always returns False.
Public Class AnonymousSecurityCheckStrategy
Implements IAuthorityCheck
Public Function IsAuthorized(ByVal resource As Object) As Boolean Implements IAuthorityCheck.IsAuthorized
Return False
End Function
End Class
Next we have our Logged-In users. They will need a Strategy too to determine their access rights.
Public Class StandardSecurityCheckStrategy
Implements IAuthorityCheck
Public Function IsAuthorized(ByVal resource As Object) As Boolean Implements IAuthorityCheck.IsAuthorized
Dim result As Boolean = PerformSomeApplicationSpecificSecurityChecks(resource)
Return result
End Function
End Class
And finally, we have our System Administrators. They can access everything so they get a Strategy that always returns True.
Public Class SysAdminSecurityCheckStrategy
Implements IAuthorityCheck
Public Function IsAuthorized(ByVal resource As Object) As Boolean Implements IAuthorityCheck.IsAuthorized
Return True
End Function
End Class
Now, all we need to do is select one of these Strategy objects at runtime and call the IsAuthorized method. In order to use these classes interchangeably, we will code against the Interface IAuthorithyCheck and not against that actual concrete class types.
One method for selecting a particular strategy could be to use a Factory. The Factory would encapsulate all the necessary logic for determining which of our various Strategy classes is the correct one to use. For example:
Public Class AuthorizationStrategyFactory
Public Shared Function GetAuthorizationStrategy() As IAuthorityCheck
If currentUserObject.IsInRole("sysadmin") Then Return New SysAdminSecurityCheckStrategy
If currentUserObject.LoggedIn = True Then
Return New StandardSecurityCheckStrategy
Else
Return New AnonymousSecurityCheckStrategy
End If
End Function
End Class
With the Strategy objects in place and a Factory to create the correct Strategy object for us, it becomes simple to perform the authorization check
Dim authorityCheck As IAuthorityCheck
authorityCheck = AuthorizationStrategyFactory.GetAuthorizationStrategy()
If authorityCheck.IsAuthorized(someResourceObject) = False Then
Else
End If
Now if the time comes for a fourth type of access to be needed (JuniorSysAdminEverythingButPayrollAccess
), we can create a new Strategy
class that implements our Interface and contains the specific algorithm appropriate for the new security check. Then we would modify the Factory
class to return that new Strategy
object when it was appropriate to do so. The last little bit of code that is calling the IsAuthorized
method does not need to change at all.
The example here was perhaps a bit contrived, but I hope that it illustrates the mechanics behind implementing the Strategy Pattern.
Also, note that the Provider Model introduced in ASP.NET 2.0 is based on strategy design pattern.
Example: Strategy Design Patterns in C#.
1. GoAlgorithm (Interface)
namespace DesignPatterns.StrategyDP {
interface GoAlgorithm {
void go();
}
2. GoByFlyingAlgorithm (Class)
class GoByFlyingAlgorithm: GoAlgorithm {
public void go() {
Console.WriteLine("Now I'm Flying");
}
}
3. GoByDrivingAlgorithm (Class)
class GoByDrivingAlgorithm: GoAlgorithm {
public void go() {
Console.WriteLine("Now I'm Driving.");
}
}
You can define more Alorithm's like "GoByMotorBikeAlgoritm" etc.
class GoByMotorBikeAlgoritm: GoAlgorithm {
public void go() {
Console.WriteLine("Now I'm Riding");
}
}
4. Vehicle (Abstract Class)
abstract class Vehicle {
private GoAlgorithm goAlgorithml;
public void setAlgorithm(GoAlgorithm Algorithm_Name) {
goAlgorithml = Algorithm_Name;
}
public void go() {
goAlgorithml.go();
}
}
5. Type of Vehicle Like 'Car', 'Vehicle' and 'Bike'
class Car: Vehicle {
public Car() {
setAlgorithm(new GoByDrivingAlgorithm());
}
}
class Helicopter:Vehicle {
public Helicopter() {
setAlgorithm(new GoByFlyingAlgorithm());
}
}
class Bike:Vehicle {
public Helicopter() {
setAlgorithm(new GoByMotorBikeAlgoritm());
}
}
6. Main
class Program {
static void Main(string[] args) {
Car F1car = new Car();
Helicopter Choper = new Helicopter();
Bike HeroHonda = new Bike();
F1car.go();
Choper.go();
HeroHonda.go();
}
}