I've been working on a particularly tricky problem recently, one that has me analysing the Form values collection that is passed in an ASP postback. Not that difficult in itself, but I don't know what values I'm looking for until runtime!
I ended up encapsulating this parsing logic in a special FormValuesParser class, but once I had finished I couldn't eliminate the bad code smell that was hanging around, and coming from someone who buys the office air-freshener, I had to do something about it.
It was easy enough to see where it was coming from. The main method in this class, ParseKeyType, was a huge switch statement. Each case block did more or less the same thing, but had to do it in subtly different ways - for example, parse the formValueKey one way for a Browse type, and a different way for a MultiSelectCheck type.
The code looked like this:
private void ParseKeyType(string formValueKey, KeyType keyType)
{
string controlMapKey;
FormKeyInfo keyInfo;
switch (keyType)
{
case KeyType.Browse:
//Perform specific parsing to Get Control Map Key
//Get Key Info
//if KeyInfo != null
//Set KeyInfo.Value
//Get key look up in ControlMap
break;
case KeyType.MultiSelectCheck:
//Perform specific parsing to Get Control Map Key
//Get Key Info
//if KeyInfo != null
//Set KeyInfo.Value
//Get key look up in ControlMap
break;
case KeyType.TextEdit:
case KeyType.Memo:
case KeyType.SpinEdit:
case KeyType.Browse_DropDown:
case KeyType.DateEdit:
case KeyType.DateTimeEdit:
//Perform specific parsing to Get Control Map Key
//Get Key Info
//if KeyInfo != null
//Set KeyInfo.Value
//Get key look up in ControlMap
break;
case KeyType.CheckEdit:
//Perform specific parsing to Get Control Map Key
//Get Key Info
//if KeyInfo != null
//Set KeyInfo.Value
//Get key look up in ControlMap
break;
case KeyType.TimeEdit:
//Perform specific parsing to Get Control Map Key
//Get Key Info
//if KeyInfo != null
//Set KeyInfo.Value
break;
}
So trying to fathom what was going on when you have to add a new KeyType in 6 months time was going to be a hassle.
If we apply the Strategy pattern, where we encapsulate the code logic within distinct Strategy classes but provide a common interface, we end up with the following, MUCH more fragrant code:
private void ParseKeyType(string formValueKey, KeyType keyType)
{
IKeyInfoStrategy keyInfoStrategy = null;
switch (keyType)
{
case KeyType.Browse:
keyInfoStrategy = new BrowseKeyInfoStrategy();
break;
case KeyType.MultiSelectCheck:
keyInfoStrategy = new MultiSelectCheckKeyInfoStrategy();
break;
case KeyType.TextEdit:
case KeyType.Memo:
case KeyType.SpinEdit:
case KeyType.Browse_DropDown:
case KeyType.DateEdit:
case KeyType.DateTimeEdit:
keyInfoStrategy = new SimpleKeyInfoStrategy();
break;
case KeyType.CheckEdit:
keyInfoStrategy = new CheckEditKeyInfoStrategy();
break;
case KeyType.TimeEdit:
keyInfoStrategy = new TimeEditKeyInfoStrategy();
break;
}
if (keyInfoStrategy != null)
{
string controlMapKey = keyInfoStrategy.GetControlMapKey(formValueKey);
FormKeyInfo keyInfo = GetKeyInfo(controlMapKey);
keyInfoStrategy.SetKeyInfoValue(keyInfo, formValueKey,
mFormValueCollection); }
}
First off, we create an IKeyInfoStrategy interface which contains the common behaviour we have abstracted, and then a concrete Strategy class for each different 'class' of KeyType.

This is a very simple example, but you can see how it will scale and lead to much easier-to-read code.