Strategy
The strategy pattern is about using composition instead of inheritence
The strategy pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. The algorithm can vary independent of clients using it
Algorithm/implementation is decoupled from its clients
This works by creating an object which wraps the behaviour we want to implement in a family of classes, allowing clients to choose which behaviour they would like to implement by referencing the interface that these behaviours implement.
Example
Definition of Classes
namespace DesignPatterns.Strategy
{
public class User {
// strategy to be used for logging in a user
// this is what we want to change depending on an implementation
private ILoginStrategy _loginStrategy { get; set; }
public string Username { get; set; }
public string Password { get; set; }
// we set the behaviour when instantiating
public User(ILoginStrategy loginStrategy)
{
this._loginStrategy = loginStrategy;
}
// we can possibly change the strategy later
public void SetLoginStrategy(ILoginStrategy loginStrategy)
{
this._loginStrategy = loginStrategy;
}
// login function that can be called by a consumer of this class
public bool Login() => _loginStrategy.Execute(Username, Password);
}
// interface to define login strategies
public interface ILoginStrategy
{
public bool Execute(string username, string password);
}
// login strategy for logging in from a local service
public class LocalLoginStrategy: ILoginStrategy
{
public bool Execute(string username, string password) => true;
}
// login strategy for logging in from a remote service
public class RemoteLoginStrategy : ILoginStrategy
{
public bool Execute(string username, string password) => false;
}
}
Usage
var user = new User(new LocalLoginStrategy()) {
Username = "user",
Password = "Password"
};
// calling this uses the LocalLoginStrategy
user.Login();
user.SetLoginStrategy(new RemoteLoginStrategy());
// calling this uses the RemoteLoginStrategy
user.Login();