The strategy design pattern allows you to encapsulate a group or family of algorithms, making them interchangeable. This allows code to determine which strategy to use at runtime. The strategy pattern is a behavioral pattern and is one of the original design patterns defined by the Gang of Four (GoF).
What Problem Does It Solve?
The strategy pattern allows you to write less fragile and coupled code. Instead of planning for every eventuality and creating code structures to deal with them, the strategy pattern gives you a clearly defined and easy to implement mechanism for algorithm selection at runtime.
The Actors
Billing Contract
The billing contract is a fairly simple interface to enforce behavior across all contracts.
Listing 1.1 – IBillingContract.cs
public interface IBillingStrategy.cs { DateTime GetDueDate(); void SendBill(string[] address); }
Abstract Billing Strategy
The Billing Strategy is the only object that inherits from the IBillingStrategy interface. However, the GetDueDate method is implemented as abstract so each child of the abstract billing strategy must create their own implementation.
Listing 1.2 – BillingStrategy.cs
public abstract class BillingStrategy : IBillingStrategy { public abstract DateTime GetDueDate(); public virtual void SendBill(string[] address) { Console.WriteLine("Sending Bill to: "); foreach(string addressPart in address) { Console.WriteLine(addressPart); } Console.WriteLine($"Due Date: {GetDueDate().ToShortDateString()}"); Console.WriteLine(); } }
Default Billing Strategy
This billing strategy will be the default to be assigned to new customers. It could also have been named Net 15.
Listing 1.3 – DefaultBillingStrategy.cs
public class DefaultBillingStrategy : BillingStrategy { public override DateTime GetDueDate() { DateTime dueDate = DateTime.Now.AddDays(15).Date; return dueDate; } }
Net 30 Billing Strategy
This billing strategy allows 30 days for payment.
Listing 1.4 – Net30BillingStrategy.cs
public class Net30BillingStrategy : DefaultBillingStrategy { public override DateTime GetDueDate() { DateTime dueDate = DateTime.Now.AddDays(30).Date; return dueDate; } }
Customer
The customer is a simple object to hold the name and address values as well as the BillingStrategy object.
Listing 1.5 – Customer.cs
public class Customer { public int ID { get; set; } public string Name { get; set; } public string StreetAddress { get; set; } public string City { get; set; } public string State { get; set; } public string PostalCode { get; set; } public BillingStrategy Strategy { get; set; } }
Implementation
The implementation is rather simple if you look past the customer creation code.
Listing 1.6 – Implementation
List<Customer> customers = new List<Customer>(); customers.Add(new Customer { City = "San Francisco", ID = 1, Name = "Digital Monikors", PostalCode = "94122", State = "CA", Strategy = new DefaultBillingStrategy(), StreetAddress = "100 W Main St" }); customers.Add(new Customer { City = "New York", ID = 2, Name = "Broadway Partners", PostalCode = "10001", State = "NY", Strategy = new Net30BillingStrategy(), StreetAddress = "100 E Main St" }); customers.Add(new Customer { City = "Denver", ID = 3, Name = "Mile High Design", PostalCode = "80201", State = "CO", Strategy = new DefaultBillingStrategy(), StreetAddress = "100 Main St" }); foreach(Customer customer in customers) { string[] address = new string[2]; address[0] = customer.Name; address[1] = $"{customer.City}, {customer.State} {customer.PostalCode}"; customer.Strategy.SendBill(address); } Console.ReadKey();
Conclusion
If you are an experienced programmer, you may have already used the Strategy design pattern in your work and possibly not known what it was called. It is a very common pattern and one of the easiest to implement.