Please check out my latest video on the Strategy Design Pattern.
This video link posted above describes two very simple and practical examples of the Strategy Design Pattern. The first example explains strategy in terms of a floor cleaning Robot. A tool that is best suited for a floor type can be attached to the floor cleaning robot and that each such tool represents a concrete strategy. Each tool has to fit a generic slot in the Robot and that represents an abstract strategy. The Robot itself represents a context. Class diagram of this scenario is
:
In another example, a simple application is shown that implements two approaches to read an XML file. The first approach loads the entire XML file into memory and uses XPath searches to find a node matching a criteria. The second approach uses line-by-line file reading approach. The class diagram of this implementation is
Source Code of the XML File Search Application:
Abstract Strategy:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace StrategyPatternConsoleApplication { //this is the abstract strategy public interface ISearchXmlFileStrategy { // All concrete strategies must implement this method string GetCustomerNameByCustomerID(String customerId, String filePath); } } |
Concrete Strategy:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml; namespace StrategyPatternConsoleApplication { //concrete strategy loads xml document into memory //then does in memoryreading public class MemorySearchXmlFileStrategy : ISearchXmlFileStrategy { /// /// Invokes strategy interface method /// ///Customer identifier ///Xml file name with path /// Customer name public string GetCustomerNameByCustomerID(String customerId, String filePath) { XmlDocument Doc = new XmlDocument(); //load the entire document into memory Doc.Load(filePath); StringBuilder CustomerName = new StringBuilder(); //local variable //stores last name and first name XmlNode RootNode = Doc.DocumentElement; XmlNode ResultNode = RootNode.SelectSingleNode("Customer[@id=" + "'" + customerId + "'" + "]"); if (ResultNode != null) { //read the last name CustomerName.Append(ResultNode.SelectSingleNode("LastName").InnerText); //append space in between last and first name CustomerName.Append(" "); //append first name CustomerName.Append(ResultNode.SelectSingleNode("FirstName").InnerText); } //return customer name formatted as last name first name return CustomerName.ToString(); } } } |
Another Concrete Strategy:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml; namespace StrategyPatternConsoleApplication { //this is another concrete strategy //that reads an xml file sequentially //may be suitable for large files //not suitable for loading into memory public class SequentialSearchXmlFileStrategy : ISearchXmlFileStrategy { /// /// Invokes strategy interface method /// ///Customer identifier ///Xml file name with path /// Customer name public string GetCustomerNameByCustomerID(String customerId, String filePath) { XmlReader Reader = XmlReader.Create(filePath); //local variable stores last name and first name StringBuilder CustomerName = new StringBuilder(); //local variable while (Reader.Read()) //read the xml file { if (Reader.IsStartElement()) //check if its starting element { var attr = Reader["id"]; //get the id attribute //if attribute matches input customer id if (attr != null && attr == customerId) { //move to last name element if (Reader.ReadToFollowing("LastName")) { Reader.Read(); //read last name //append the last name value CustomerName.Append(Reader.Value); } if (Reader.ReadToFollowing("FirstName"))//move to first name element { Reader.Read(); //read first name //append space between last name and first name CustomerName.Append(" "); //append the first name value CustomerName.Append(Reader.Value); break; //found record get out of loop } } } } Reader.Close(); //close the reader //return the formatted full name return CustomerName.ToString(); } } } |
Context:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace StrategyPatternConsoleApplication { //this is the context class public class CustomerFinder { //holds a reference to the strategy ISearchXmlFileStrategy _strategy = null; /// /// Strategy setter /// ///The concrete strategy public void SetStrategy(ISearchXmlFileStrategy strategy) { _strategy = strategy; } //invoke strategy method /// /// Invokes strategy interface method /// ///Customer identifier ///Xml file name with path /// Last name and first name as string public String GetCustomerNamebyId(String customerId, String filePath) { return _strategy.GetCustomerNameByCustomerID(customerId, filePath); } } } |
Client:
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace StrategyPatternConsoleApplication { class Program { /// /// Main Method - entry point to the console application /// ///Command Line arguments static void Main(string[] args) { Console.WriteLine("Please supply value of customer id"); String Id = Console.ReadLine(); ISearchXmlFileStrategy Strategy = new MemorySearchXmlFileStrategy(); CustomerFinder Context = new CustomerFinder(); Context.SetStrategy(Strategy); String CustomerName = Context.GetCustomerNamebyId(Id, "C:\\Code\\StrategyPatternSolution\\CustomerData.xml"); //display result if (String.IsNullOrEmpty(CustomerName)) { Console.WriteLine("No Customer Found"); } else { Console.WriteLine(CustomerName); } Console.WriteLine("Press any key to exit..."); //keep the console window open till the user presses any key Console.ReadKey(); } } } |
All other details on the Strategy Design Pattern are included in this video. I’d love you get your feedback and would also like to know how you have applied this design pattern.