|
|
Implementing Strategy Pattern in C# Written on November 6, 2009, by Mehmetali Shaqiri. |
As a software developer, my primary goal is making my code correct, elegant, extensible and efficient. Although simplistic, every programming decision I make is largely based on maintainability. I’m very loyal to Don’t Repeat Yourself (DRY) principle.
Back at my studies (Computer Sciences in SEE-University) I had the chance to read C# 3.0 Design Patterns by Judith Bishop, a great book which covers the full set of 23 patterns that were originally proposed in Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides’s Design Patterns: Elements of Reusable Object-Oriented Software in 1994. By reading this book, I’ve acquired skills in: programming design patterns, basic UML modeling notation, ability to select appropriate patterns for given scenarios and advanced language features of C# 3.0. I highly recommend this book.
why strategy pattern?
There are cases that for a given problem you could apply various algorithms. If you keep all your algorithms in single class as a result you’ll have a very messy code with lots of conditional statements. It may work but it’s very hard to maintain, you may not recognize it after a while, it’s not the right way of doing it and it can be your worst nightmare. The ultimate tool in making your code maintainable is to keep it as simple as possible.
The strategy pattern enables a client to choose which algorithm to use from a range of supported algorithms and gives it a simple way to access it for ex. you have an News syndication service and you want to give you users the ability to grab those news in RSS or ATOM. In this case the scenario was to choose whether to process xml or text files.
Design
The key players for strategy patterns are as follows:
- Context - Contains an IStrategy object’s algorithm in which we’re working on
- IStrategy - Defines an interface common to all the strategies
- TextFileImporter, XmlFileImporter - Classes that include algorithms that implement the IStrategy interface
Below you have the UML diagram:
Strategy Pattern UML Diagram
Implementation
The IStrategy interface is used to define a contract that is shared between TextFileImporter and XmlFileImporter.
namespace FileImporter.BusinessLogic { /// /// A common interface to all supported file types /// public interface IStrategy { XDocument ImportOrders(); } }
Both TextFileImporter and XmlFileImporter classes implement IStrategy interface and they have a constructor which takes the file path as parameter.
namespace FileImporter.BusinessLogic { public class TextFileImporter:IStrategy { private string _path; public TextFileImporter(string path) { this._path = path; } #region IStrategy Members public XDocument ImportOrders() { XDocument doc = XDocument.Load(_path); return doc; } #endregion } public class XmlFileImporter:IStrategy { private string _path; public XmlFileImporter(string path) { this._path = path; } #region IStrategy Members public XDocument ImportOrders() { XDocument doc = new XDocument(); doc = XDocument.Load(_path); return doc; } #endregion } }
Here the context FileImporter points to a strategy and delegates to it. If a TextFileImporter is passed to the constructor than the TextFileImporter algorithm will take place and vise versa.
namespace FileImporter.BusinessLogic { public class FileImporter { private IStrategy _strategy; public FileImporter(IStrategy strategy) { _strategy = strategy; } public void ImportOrders() { XDocument xmlDoc = _strategy.ImportOrders(); SqlHelper.InsertOrders(xmlDoc); } } }
And here is where the decision making process takes place. Here the client can choose whether to use the XmlFileImporter or TextFileImporter. This is a code snippet from a windows service (more on this on later posts) which monitors a given directory and whenever a new file is created, it checks what type of file is (.xml or .txt) and based on the file extension if uses an appropriate strategy.
private void watcher_Created(object sender, System.IO.FileSystemEventArgs e) { if (File.Exists(e.FullPath)) { FileImporter.BusinessLogic.FileImporter importer = null; string ext = e.Name.Substring(e.Name.IndexOf('.'), 4).ToLower(); switch (ext) { case ".xml": importer = new FileImporter.BusinessLogic.FileImporter(new XmlFileImporter(e.FullPath)); break; case ".txt": importer = new FileImporter.BusinessLogic.FileImporter(new TextFileImporter(e.FullPath)); break; default: break; } if (importer != null) { Thread thr = new Thread(new ThreadStart(importer.ImportOrders)); thr.Start(); } } }
Hope this helps
Tags: C#, Design Patterns. If you would like to leave a comment, click here: Comment. or stay up to date with this post via RSS, or you can Trackback from your site.
Leave a Comment
If you would like to make a comment, please fill out the form below.




