Thursday, September 23, 2010

A substitute of switch.. case

Problem: is there anyway to replace the uses of 'switch..case' because I have many 'cases' in the switch statement which is hard to maintain.

Solution: you may try to replace the 'switch..case' with Dictionary + reflection. By using this plug and play design, you will be able to expand your program easily.

For example, you have a class call ProcessSwitches which handles the process request:
    public class ProcessSwitches
{
public string Process(int process_index)
{
string result = string.Empty;

switch (process_index)
{
case 0:
result = this.Cleaning();
break;
case 1:
result = this.Polishing();
break;

//other processes go here...

default:
result = "underdefined";
break;
}

return result;
}

string Cleaning()
{
return "Cleaning process.";
}

string Polishing()
{
return "Polishing process";
}

// many other methods here...
}
Of course, whenever you need to provide a new service, you have to add a new 'case' and a method specifically for that purpose. In case you have a very long list of services, you may not want to see a many hundred lines of cases here.

To overcome this problem, we need to define an interface which will serve the common method call. Then, each service will be converted from method (ie, ProcessSwitches.Cleaning and ProcessSwitch.Polishing) to class individually.
    public interface IProcess
{
string Execute();
}

public class Cleaning : IProcess
{
public string Execute()
{
return "cleaning..";
}
}

public class Drying : IProcess
{
public string Execute()
{
return "drying..";
}
}
After converting the methods to classes, we need to create a registry (or repository) to store the service index and class mapping.
    public class ProcessRegistry : Dictionary
{
public ProcessRegistry()
{
this.Init();
}

void Init()
{
this.Add(0, typeof(Cleaning));
this.Add(0, typeof(Polishing));

//you may add more other process here.
//...
}
}
The final step will be replacing the 'switch..case' by the ProcessRegistry that we have created. Since the ProcessRegistry was inherited from Dictionary class, you may retrieve the class type that you have setup in the ProcessRegistry.Init method.
    public class ProcessSwitchesNew
{
ProcessRegistry registry = new ProcessRegistry();

public string Process(int process_index)
{
string result = string.Empty;
Type type;

// now, you may replace the 'switch..case' with Dictionary class.
// which allows you to provide more services without modifying this method.
if (registry.TryGetValue(process_index, out type))
{
// instantiate the object.
object obj = Activator.CreateInstance(type);
// cast it as IProcess interface.
IProcess process = obj as IProcess;

if (process != null)
{
// execute the process.
result = process.Execute();
}
}

return result;
}
}
Now, what is the benefit you receive from this design?

Benefits:
- You can create and test the service class individually or pass the class development to your team member.

- Easier to increase the number of cases without have the mess around within the 'switch..case' statement. What you need to do is to add a new line in the ProcessRegistry.Init method. Anyone can do it easily.

- The service classes (such as Cleaning and Polishing) can be reuse without have to dismantle the 'switch..case'. Just setup a new registry class and load the necessary class types.

Of course, everything comes in costs. There are disadvantages in this design:
- You might have too many classes.
- The program might run slower due to the use of reflection (ie, Activator) to instantiate the class.

No comments:

Post a Comment