Thursday, July 07, 2005

Design Pattern - Strategy


Today out of curiosity, I was experimenting with strategy design pattern.
Here's the outcome of my experiment.

Strategy pattern falls under the Behavioral category.

The Intent:
Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
The strategy pattern embodies two fundamental principle of object oriented programming. First encapsulate the concept which changes behaviour and program against the interface.

I had written a small notepad application to illustrate the use of strategy.
Other things remaining same, the dynamics of the pattern is applied when using the "find" method in the notepad. Based on the user's selection either a normal "find" alogrithm is invoked or a "regex" based algorithm is used.

The application being trivial, you wont find much regex code. Its used only for demonstration purpose.

Dissecting the application

(1) Program against the interface


// IFind.cs - This would be our strategy interface
using System;
using System.Windows.Forms;
namespace DesignPatterns
{
public interface IFind
{
int Find(RichTextBox textControl,string str);
}
}

// NormalFind.cs - An implementation of 1st algorithm - ConcreteStrategyA
using System;
using System.Windows.Forms;

namespace DesignPatterns
{
public class NormalFind : IFind
{
static int filePointer = 0;
public NormalFind()
{}

int IFind.Find(RichTextBox textControl, string str)
{
int start = -1;
try
{
start = textControl.Text.IndexOf(str, filePointer);
int len = str.Length;

textControl.Select(start, len);
textControl.Focus();
filePointer = start + len;
}
catch (Exception e)
{
e.ToString();
MessageBox.Show("Reached End of Document.");
filePointer = 0;
}
return start;
}
}
}

// RegexFind.cs - An implementation of 2nd algorithm - ConcreteStrategyB
using System;
using System.Windows.Forms;
using System.Text.RegularExpressions;
using System.Diagnostics;

namespace DesignPatterns
{
public class RegexFind : IFind
{
static int filePointer = 0;
int start = -1;
public RegexFind()
{}

int IFind.Find(RichTextBox textControl,string str)
{
Regex r = new Regex(str);
try
{
Match m = r.Match(textControl.Text,filePointer, textControl.TextLength);
Trace.Assert(m.Success);
textControl.Select(m.Index, m.Length);
textControl.Focus();
filePointer = m.Index + m.Length;
start = m.Index;
}
catch (Exception e)
{
e.ToString();
MessageBox.Show("Reached End of Document.");
filePointer = 0;
}
return start;
}
}
}

// FindManager.cs - Handles the strategy context -
using System;
using System.Windows.Forms;
namespace DesignPatterns
{
public class FindManager
{
IFind find;
RichTextBox rtb;

public FindManager()
{}

public FindManager(RichTextBox rbox)
{
this.rtb = rbox;
}

public void SetFindStrategy( IFind myfind)
{
this.find =myfind;
}

public int Find(string findString)
{
return find.Find(rtb, findString);
}
}
}

// The client code extract
private void btnFind_Click(object sender, System.EventArgs e)
{
FindManager fm = new FindManager(this.richTextBoxInstance);
// dynamically set the strategy
if (chkRegEx.Checked == true)
fm.SetFindStrategy(new RegexFind());
else
fm.SetFindStrategy(new NormalFind());

fm.Find(txtFind.Text);
}

For more information go to
www.dofactory.com
davidhayden.com/blog
Also refer the GOF pattern book.

UML class diagram has been adapted from www.dofactory.com. I hope they don't mind it.



Enjoy patterning :)

2 comments:

Anonymous said...

Hi Rajesh,

Read your post.. keep them coming.. but do remember that now u have readers of your blog who are not .net savy as u are... I will have more questions to ask now...

Cheers and happy blogging :D
Chetan

Rajesh Pillai said...

Hi Chetan,
You are always welcome :)
Rajesh