In my previous post I talked about how if-else and switch statements are very similar in that they both ignore the problem of combining data with code.
Today I am going to show you how to refactor the switch statements to alleviate that problem.
There are some varied opinions on refactoring switch statements which I believe derive from trying to treat all switch statements as the same. I want to look at the kinds of switch statements that exist and why I recommend to refactor each one in a particular way.
Data to data
The first most obvious kind of switch statement is one that maps one form of data to another form of data.
switch (state)
{
case "Florida": return "Tallahassee";
case "Idaho": return "Boise";
case "Arizona": return "Phoenix";
case "South Carolina": return "Columbia";
}
This example is clearly mapping one piece of data to another. The best refactor for this situation is to use a map. In C# it is a dictionary, in Java a map.
var stateToCapitolMap = new Dictionary<string, string>()
{
{"Florida", "Tallahassee"},
{"Idaho", "Boise"},
{"Arizona", "Phoenix"},
{"South Carolina", "Columbia"}
};
return stateToCapitolMap[state];
I cannot believe how many people argue against this refactoring. It doesn’t look like much, but we have greatly separated logic from data and increased the maintainability of the code.
Before our refactoring, consider, how you would be able to read all the states and capitols from a file and insert them into the switch statement? The only possible way would be through code generation. Clearly this indicates a coupling of code and data. The switch statement is formatted in such a way that it almost looks like data, but don’t let that fool you, it is code.
Consider the refactored example. If we want to read the values from a file, it is simple. So simple, that I’ll even show the code right here.
var stateToCapitolMap = new Dictionary<string, string>();
foreach (string line in File.ReadAllLines("StatesAndCapitols.txt"))
{
string[] stateCapitol = line.Split(',');
stateToCapitolMap.Add(stateCapitol[0], stateCapitol[1]);
}
return stateToCapitolMap[state];
Data to action
This kind of switch statement appears different than data to data, but it is actually very similar. In this case we are mapping some data to a direct action that should be performed given that data.
Often this form of logic can be disguised by multiple actions happening in a case statement.
switch (move)
{
case "Up": MoveUp();
break;
case "Down": MoveDown();
break;
case "Left": MoveLeft();
break;
case "Right": MoveRight();
break;
case "Combo":
MoveUp();
MoveUp();
MoveDown();
MoveDown();
break;
}
We can take the same approach here because really this is a form of mapping data to data. The second data item is essentially the name of a method to call to perform an action. We can illustrate this intent easily in C#. (In Java, you will need to wrap the action into a set of classes with a common interface.)
var moveMap = new Dictionary<string, Action>()
{
{"Up", MoveUp},
{"Down", MoveDown},
{"Left", MoveLeft},
{"Right", MoveRight},
{"Combo", () => { MoveUp(); MoveUp(); MoveDown(); MoveDown(); }}
};
moveMap[move]();
What we are essentially doing now is a dynamic look-up of the method to call based on the data. We could even make this example data driven from a text file that specified how to map a move to a method name or list of method names, but that is far beyond on the scope of this post, and I don’t think I would recommend it unless you have a really good reason.
Data to multiple actions
If you are familiar with the techniques of refactoring switch statements, you make be shaking your head by now saying “that guy is wrong, he needs to use a factory.” Okay, well now we are going to do it.
In the data-to-action refactoring, I opted for the simplest solution that can work, instead of trying to over solve the problem by adding complexity in the form of a factory.
But, what happens when you have multiple switch statements in your code that operate on the same set of data?
switch (move)
{
case "Up": MoveUp();
break;
case "Down": MoveDown();
break;
case "Left": MoveLeft();
break;
case "Right": MoveRight();
break;
case "Combo":
MoveUp();
MoveUp();
MoveDown();
MoveDown();
break;
}
// ... somewhere else
switch (move)
{
case "Up":
moveName = "Basic Up Move";
break;
case "Down":
moveName = "Basic Down Move";
break;
case "Left":
moveName = "Basic Left Move";
break;
case "Right":
moveName = "Basic Right Move";
break;
case "Combo":
moveName = "Up Up Down Down Combo Move";
break;
}
Sure, we could refactor these both into maps or dictionaries. But what will happen when we try and add a new move? We’ll have to remember to add logic in both places or we’ll have a problem. In the prior example we recognized that data was being mapped to an action, so we represented that as succinctly in code as possible.
In this example, the same data is being mapped to some data that describes a move and actions to perform. We need some way to house these attributes that belong to the data we are switching on together, and we would like to have this all in one place, so we don’t have to change the code in multiple places.
Our best solution here is to use a factory that gives us the right kind of object that implements the behavior that should be tied to the data we are currently switching on.
public interface IMove
{
void DoMove();
string GetFriendlyName();
}
public class UpMove : IMove
{
public void DoMove()
{
// Do the move
}
public string GetFriendlyName()
{
return "Basic Up Move";
}
}
public static class MoveFactory
{
private static Dictionary<string, Func<IMove>> moveMap = new Dictionary<string, Func<IMove>>()
{
{"Up", () => { return new UpMove(); }},
{"Down", () => { return new DownMove(); }},
{"Left", () => { return new LeftMove(); }}
// ...
};
public static IMove CreateMoveFromName(string name)
{
return moveMap[name]();
}
}
You can see here that we are creating a factory which contains a dictionary which maps a move name to what kind of object to create. Each move implements a common IMove interface. (I only show some of the implementation here.)
Now in our code we can replace those switch statements with polymorphic behavior from our object returned from the factory.
IMove move = MoveFactory.CreateMoveFromName(name); move.DoMove(); String friendlyName = move.GetFriendlyName();
The nice thing about this implementation is that if we try to add a new move the IMove interface will require us to implement all the proper methods. We make a change in one place and the compiler reminds us what we need to do.
Don’t jump straight to the factory
You may have heard the argument between using a factory or a dictionary for refactoring switch statements before. What I am trying to show in this blog post is that it depends on your situation.
The simplest solution is a dictionary or map. Once you have a second place you are mapping the same data, you should move to a factory. The factory then contains the mapping between a piece of data and a class.
I also wanted to note here that I didn’t use enumerations. In real code you should. I avoided them here to prevent adding one more layer of abstraction so that my example would not require as much explanation.


In Java, the simplest solution is often an enum.
enum Move {
Up(“Basic Up Move”) {
@Override
public void DoMove() {
MoveUp();
}
},
Down(“Basic Down Move”) { … },
(Left, right, combo …);
private final String friendlyName;
private Move(String friendlyName) {
this.friendlyName = friendlyName;
}
public String getFriendlyName() {
return friendlyName;
}
}
Yes, this makes it impossible to read from a file to know what your actions are, but if that’s not a requirement, Java enums are generally pretty good at one-way mappings.
By: configurator on August 17, 2010
at 11:01 am
Excellent point! Thanks for the comment, I didn’t put a Java solution here, but that is one that I frequently use, although I didn’t consider using an anonymous override int he constructor. It is certainly most appropriate in my last example.
By: jsonmez on August 17, 2010
at 11:06 am
[...] my next post, I will show you how to take switch statements and refactor them into a better form that separates [...]
By: Switch is Just a Fancy If Else « Making the Complex Simple on August 17, 2010
at 12:30 pm
[...] Pulling out the Switch: It’s Time for a Whooping « Making the Complex Simple – John Sonmez takes a look at the different types of switch statement that there are, looking at what the most appropriate refactoring for each is, considering the cases Data to Data, Data to Action and Data to Multiple Action. [...]
By: The Morning Brew - Chris Alcock » The Morning Brew #667 on August 18, 2010
at 12:37 am
What I can’t believe is that I just figured out the “It’s time for a whooping” joke. I need more caffeine this morning.
On the plus side, I did implement the map function in some code I’m writing, a very elegant solution. Many thanks!
By: KevDog on August 23, 2010
at 7:08 am
Heh, if you’ve never been whooped by a switch, the reference might be a little obscure.
Glad I could be of help.
By: jsonmez on August 23, 2010
at 7:25 am
[...] Pulling out the Switch: It’s Time for a Whooping [...]
By: Explaining What Action<> And Func<> Are « Making the Complex Simple on September 24, 2010
at 6:45 am
I’ve been using this technique a lot lately and was curious as to how you would recommend refactoring this little bit of fun:
public static DataFileParser GetParser(DataFile dataFile)
{
switch ((FileType)dataFile.ValidationFormat.FileType)
{
case FileType.PDF:
return new PdfParser(dataFile);
case FileType.Image:
return new ImageParser(dataFile);
case FileType.CsvWithHeaderRow:
return new CsvParser(dataFile, true);
case FileType.Csv:
return new CsvParser(dataFile, false);
default:
break;
}
throw new NotImplementedException(“There is no parser for ” + dataFile.ValidationFormat.FileType.ToString());
}
By: KevDog on October 18, 2010
at 10:45 am
I see 2 options.
1) a map of FileType to DataFileParser
2) add a static FileType property to the DataFileParser class and query against the DataFileParser implementations to find who supports the particular type.
Yeah, I guess #1 is easier ; )
Hope this helps, T.J.
By: TJB on October 23, 2010
at 10:26 pm
[...] posted a question in response to my post Pulling out the Switch: It’s Time for a Whooping and I thought it would be good to go ahead and answer it as a post since it is a pretty interesting [...]
By: Refactoring Switches Advanced « Making the Complex Simple on October 19, 2010
at 3:34 pm
this post is awesome. I may sound silly. switch statement has default supported. its kind of fallback. Where as Dictonary doesn’t has default element. so how do we support that?
var stateToCapitolMap = new Dictionary()
{
{“Florida”, “Tallahassee”},
{“Idaho”, “Boise”},
{“Arizona”, “Phoenix”},
{“South Carolina”, “Columbia”}
};
return stateToCapitolMap[nostate];
By: sureshvr on December 2, 2011
at 2:35 pm
Thanks, great observation:
http://simpleprogrammer.com/2011/08/14/making-switch-refactorings-better-defaultable-dictionary/
I actually created a defaultable dictionary that solves this problem.
By: jsonmez on December 2, 2011
at 2:36 pm
rather than how do we support. my question should have been how we handle it?
By: sureshvr on December 2, 2011
at 2:37 pm
you are fast. thanks for your post. your post specially these kinds are addicting for me. Looking forward for more great post.
By: sureshvr on December 2, 2011
at 2:40 pm
[...] Pulling out the Switch: It’s Time for a Whooping [...]
By: Refactoring Switches to Classes « Making the Complex Simple on February 21, 2012
at 2:29 pm