Tuesday, February 26, 2008

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.

 

Tuesday, February 26, 2008 8:48:16 PM (GMT Standard Time, UTC+00:00) | Comments [0] | Patterns#
Comments are closed.
Search
Archive
Links
Categories
Admin Login
Sign In
Blogroll