I want to show you how to apply a simple refactoring trick to a common pattern, the "switch case
" statement.
Please take a look at the following program (a console app):
class Program
{
private static string options = null;
private static readonly Type sportsEnumType = typeof(SportNews.Sports);
static void Main(string[] args)
{
SportNews news = new SportNews();
while (true)
{
Console.WriteLine();
DisplayOptions();
string key = Console.ReadKey().KeyChar.ToString();
Console.WriteLine();
try
{
SportNews.Sports sport = (SportNews.Sports)(Enum.Parse(
sportsEnumType, key));
news.DisplayNews(sport);
}
catch(Exception ex)
{
Console.WriteLine(ex);
Console.ReadLine();
return;
}
}
}
private static void DisplayOptions()
{
if (options == null)
{
StringBuilder optionsBuilder = new StringBuilder();
FieldInfo[] enumFields = sportsEnumType.UnderlyingSystemType.GetFields(
BindingFlags.Public | BindingFlags.Static);
foreach (FieldInfo enumField in enumFields)
{
object enumValue = enumField.GetRawConstantValue();
SportNews.Sports sport = (SportNews.Sports)(enumValue);
optionsBuilder.AppendFormat("To display the news for {0} press {1}\n",
sport, enumValue);
}
options = optionsBuilder.ToString();
}
Console.WriteLine(options);
}
}
public class SportNews
{
public enum Sports
{
Soccer = 0,
BasketBall = 1,
Rugby = 2,
VolleyBall = 3
}
public void DisplayNews(Sports sport)
{
switch (sport)
{
case Sports.Soccer:
DisplayNewsForSoccer();
break;
case Sports.BasketBall:
DisplayNewsForBasketBall();
break;
case Sports.Rugby:
DisplayNewsForRugby();
break;
case Sports.VolleyBall:
DisplayNewsForVolleyBall();
break;
default:
throw new NotImplementedException(string.Format(
"The method for the sport {0} is not implemented", sport));
}
}
private void DisplayNewsForSoccer()
{
Console.WriteLine("Displaying News for Soccer");
}
private void DisplayNewsForBasketBall()
{
Console.WriteLine("Displaying News for BasketBall");
}
private void DisplayNewsForRugby()
{
Console.WriteLine("Displaying News for Rugby");
}
private void DisplayNewsForVolleyBall()
{
Console.WriteLine("Displaying News for VolleyBall");
}
}
What does this do? Well, simply ask the user to press a given key to execute a determined action.
The running program looks like this:
Very simple, isn't?
This is fine for the number of alternatives that we are going to handle, but, what about if you add more items (+10) to the enum
, you would need to add more cases to the switch
statement, and so on. This is a very error prone process and also a maintenance nightmare.
What to do then? Well, the solution is very simple, you would need to change the switch
statement by a lookup table, a Dictionary
object is a good candidate to do this.
SHOW ME THE CODE!!. Here it is:
First let's create our Dictionary
instance in the SportNews
class constructor:
private Dictionary<Sports, Action> lookupTable;
public SportNews()
{
lookupTable = new Dictionary<Sports, Action>()
{
{ Sports.Soccer, DisplayNewsForSoccer },
{ Sports.BasketBall, DisplayNewsForBasketBall },
{ Sports.Rugby, DisplayNewsForRugby },
{ Sports.VolleyBall, DisplayNewsForVolleyBall }
};
}
Now let's change the DisplayNews
method to get rid of the switch
statement, it will end up as:
public void DisplayNews(Sports sport)
{
Action displayMethod;
if (lookupTable.TryGetValue(sport, out displayMethod))
{
displayMethod.Invoke();
}
else
{
throw new NotImplementedException(string.Format(
"The method for the sport {0} is not implemented", sport));
}
}
Isn't this more simple and clean?
Obviously, this code could be refactored even more, but for the purpose of the article, I think it is fine.
The final working demo can be found here.
Shameless plug: You can check this article on my blog here.