C# Design Pattern : Strategy
The strategy design pattern defines a means by which we decouple a family of related algorithms and make them interchangeable among one another within a required context.
The interchangeable bits are referred to as strategies, generally one would define a strategy by way of interface or abstract class e.g.
interface IStrategy { bool DoSomething(); } /* abstract class Strategy { abstract public bool DoSomething(); } */ class StrategyA : IStrategy { public bool DoSomething() { return true; } } class StrategyB : IStrategy { public bool DoSomething() { return true; } }
In the following snippet (console app) a strategy gets assigned according to what the user passed to the command-line - which represents our context.
class Context { private IStrategy _Strategy; public Context(IStrategy Strategy) { this._Strategy = Strategy; } public bool DoSomething() { return this._Strategy.DoSomething(); } } class Program { static void Main(string[] args) { Context ctx = ((args.Length > 0) && (args[0] == "a")) ? new Context(new StrategyA()) : new Context(new StrategyB()); ctx.DoSomething(); } }
It is rather obvious to imagine the usefulness of this pattern in the real world.
Imagine for a moment that we need to copy a file to a server somewhere, there is a few things (among others) to consider:
- Location of the server in relation to the file we want to copy, outside/inside our network?
- Available transfer methods ftp/http(soap)/ssh etc
If we implement the strategy pattern, we're basically going to decouple & handle these various scenarios using separate strategy classes - according to the context the program finds itself in (e.g. the app is outside the LAN - use FTP strategy), we'll know which strategy to use.
The beauty of this approach is that since its decoupled, the app doesn't need to have knowledge about the implementations of our strategies. When creating a strategy we simply need to implement the Strategy interface / abstract class and ensure that the behavior from our implementations are predictable.
The following snippet is an example of this ftp/local scenario, we've got a FTPStrategy and a LocalStrategy (its behavior might not be completely predictable e.g. error handling wise):
interface IStrategy { public void UploadFile(String fullname, String folder); } class FTPStrategy : IStrategy { public void UploadFile(string fullname, string folder) { FileInfo fileInfo = new FileInfo(fullname); Uri requestUri = new Uri(String.Concat("ftp://example.com", folder, "/", fileInfo.Name)); FtpWebRequest ftpRequest = (FtpWebRequest)FtpWebRequest.Create(requestUri); ftpRequest.Method = WebRequestMethods.Ftp.UploadFile; ftpRequest.Credentials = new NetworkCredential("username", "password"); using (Stream writer = ftpRequest.GetRequestStream()) { byte[] contents = File.ReadAllBytes(fullname); writer.Write(contents, 0, contents.Length); } } } class LocalStrategy : IStrategy { public void UploadFile(string fullname, string folder) { FileInfo fileInfo = new FileInfo(fullname); byte[] contents = File.ReadAllBytes(fullname); File.WriteAllBytes(String.Concat("c:", folder, "/", fileInfo.Name), contents); } }
In the following snippet the dev needs to tell the app via enum which strategy to use, it would probably make sense to rather detect which strategy is the most appropriate to use in context - instead of requiring the dev to specify strategy via enum, but hey ;)
class Context { private IStrategy _Strategy; public Context(Strategies strategy) { if (strategy == Strategies.FTP) { _Strategy = new FTPStrategy(); } else if (strategy == Strategies.Local) { _Strategy = new LocalStrategy(); } } public void UploadFile(string fullname, string folder) { this._Strategy.UploadFile(fullname, folder); } } enum Strategies { FTP, Local } class Program { static void Main(string[] args) { Context ctx = new Context(Strategies.FTP); ctx.UploadFile(@"c:\somefolder\xls.xml", "/Skool"); } }
Incidently I recently used this pattern in one of my PHP projects, have a look over here.
Additional Reading
http://www.dofactory.com/Patterns/PatternStrategy.aspx
http://www.netobjectives.com/PatternRepository/index.php?title=TheStrategyPattern
Posted by - Christoff Truter
Date - 2011-02-10 17:10:41
Comments - 0
Date - 2011-02-10 17:10:41
Comments - 0
ASP.net (IIS): IE8 - Compatibility view
Internet explorer 8 adheres to industry standards (W3C) a lot more than previous versions of the browser - unfortunately it comes with a price (e.g. with regards to how IE renders your website(s)).
Microsoft did however think about this problem and introduced what they call "compatibility view", basically we've got a toggle button in the browser, like seen in the following image:
When we press the button, the site renders using the IE7 engine (solving our immediate problem).
It would however make a lot more sense if the visitor of the website didn't need to press the button, for that reason we can put the following meta tag into our website.
Note that this tag needs to appear before any other element inside the html page's head tag (except the title and other meta tags, else the browser will simply ignore it), you will notice the "compatibility view" button disappearing - the visitor can't disable compatibility.
I did however see an interesting issue while settings emulation on one of our ASP.NET projects - since we've got a server side head tag, it won't necessarily be possible to always place the meta tag we're its supposed to be.
We can luckily additionally set compatibility via the web.config like this:
<system.webServer> <httpProtocol> <customHeaders> <clear /> <add name="X-UA-Compatible" value="IE=EmulateIE7" /> </customHeaders> </httpProtocol> </system.webServer>
This causes IIS to automatically pass emulation via HTTP response header across all pages.
Additional Reading:
http://msdn.microsoft.com/en-us/library/cc288325(v=vs.85).aspx
http://msdn.microsoft.com/en-us/cc817572.aspx
http://msdn.microsoft.com/en-us/cc817573.aspx
Posted by - Christoff Truter
Date - 2011-02-10 17:09:35
Comments - 0
Date - 2011-02-10 17:09:35
Comments - 0
First 6 7 8 9 10 11 12 13 14 15 Last / 62 Pages (124 Entries)