Switch is EVIL! (Part 3a)

Why 3a? Why not Part 4? Well, a lot of people have messaged me that I am writing code in JavaScript, which due to its dynamic nature can do such things conveniently, but how about static languages like C++, Java or C#? So this post is basically same as Part 3 but using static languages.

So let's get rolling

switch-case in any language leads to problems, especially modification of existing code, regression testing, not to mention that the code starts to bloat up when more cases are added

Let's look at the beast
class Evil {
public String changeCase(String caseType, Stringwords) {
// We support lower and camel cases
// Sanitize the user input
caseType = caseType
.trim()
.toLowerCase();
// Accumulate output in StringBuilder
StringBuilder result = new StringBuilder();
if (caseType.equals("lower")) {
// All words are converted to lower
// And then concatenated
for (String word : words) {
result.append(
word
.trim()
.toLowerCase()
);
}
} else if (caseType.equals("camel")) {
// First word is all lower
result.append(
words[0]
.trim()
.toLowerCase()
);
// Subsequent words are
// first -> upper
// rest -> lower
for (int offset = 1;
offset < words.length;
offset++) {
// First letter is upper
result.append(
words[offset]
.substring(0, 1)
.toUpperCase()
);
// Remaining letters are lower
result.append(
words[offset]
.substring(1)
.toLowerCase()
);
}
}
return result.toString();
}
public static void main(String[] args) {
Evil obj = new Evil();
String output = obj.changeCase("lower", "This", "Word");
System.out.println(output);
}
}
view raw SwitchCase.java hosted with ❤ by GitHub

Implementing function maps in Java and C# are nearly as easy as JavaScript. The simplest way is to use delegates in C#. Other ways include Action<>, Func<> and Predicate<>. Java too has Function<>, Consumer<> and Predicate<>. Everything else failing, we can still fall back to Interfaces (or abstract classes in languages like C++).

We will use the simplest of ways here.. interface
/**
* interface specifies just one method
* which converts the case and returns back
*
* Various converters will implement this
*. lower, camel, proper, snake etc
*/
interface CaseConverter {
String convert(Stringwords);
}

Now let’s refactor our application. We will cleave out code from individual if-else blocks and make them separate interface implementations. These implementation can be written in separate files, independent of other converters and make the unit testing much simpler

lower CaseConverter
/**
* LowerConverter implements CaseConverter
* and converts all words to lower case
*/
class LowerConverter implements CaseConverter {
@Override
public String convert(Stringwords) {
// Accumulate result in StringBuilder
StringBuilder result = new StringBuilder();
// All words are converter to lower
// And then concatenated
for (String word : words) {
result.append(
word
.trim()
.toLowerCase());
}
return result.toString();
}
}

Now we are focussing on ONE case at a time, which leads to better unit testing and no modification is required in a HUGE switch-case of if-else ladder

camel CaseConverter
/**
* CamelConverter makes
* first word all lower
* subsequent words firt letter upper, rest lower
* "TWO", "WORDS" -> "twoWords"
*/
class CamelConverter implements CaseConverter {
@Override
public String convert(Stringwords) {
// Accumulate result in StringBuilder
StringBuilder result = new StringBuilder();
// First word is all lower
result.append(
words[0]
.trim()
.toLowerCase()
);
// Subsequent words are
// first -> upper
// rest -> lower
for (int offset = 1;
offset < words.length;
offset++) {
// First letter is upper
result.append(
words[offset]
.substring(0, 1)
.toUpperCase()
);
// Remaining letters are lower
result.append(
words[offset]
.substring(1)
.toLowerCase());
}
return result.toString();
}
}

We have separated out each case (if block) into separate implementations, so nows it’s time to factor our main CaseConverter code. This is the crux of the whole exercise –
Replace switch-case/if-else ladder with a MAP

Convert EVIL into Angel
/**
* Our EVIL code has turned into an angel
* We now have a small and maintanable code
*/
class Angel {
// Get rid of old switch-case/if-else ladder
// Replace it with a sweet map
HashMap<String, CaseConverter> converters =
(HashMap<String, CaseConverter>)
Map.of(
"lower", new LowerConverter(),
"camel", new CamelConverter()
);
public String changeCase(String caseType, Stringwords) {
// We support lower and camel cases
// Sanitize the user input
caseType = caseType
.trim()
.toLowerCase();
// Lookup which converter the user wants
CaseConverter converter = converters.get(caseType);
if (converter!=null)
return converter.convert(words);
else
return null;
}
public static void main(String[] args) {
Angel obj = new Angel();
String output = obj.changeCase("camel", "This", "Word");
System.out.println(output);
}
}
view raw CaseAngel.java hosted with ❤ by GitHub

So there.. we have eliminated switch-case/if-else ladder from a static language like Java. We can do similar things in C#, C++ and others too.
I have not focussed on optimisation as the idea was to keep the code simple to understand the conversion process, but we can use Function<> or even SAM (Single Abstract Method) implementation, instead of creating ENTIRE class to implement individual converters.
You feedback, correction and improvement suggestions are welcome

Switch is EVIL Series

  1. Switch is EVIL! (Part 1) – Convert it to arrays
  2. Switch is EVIL! (Part 2) – Convert it to maps
  3. Switch is EVIL! (Part 3) – Create function maps
  4. Switch is EVIL! (Part 3a) – Implementing in Java
  5. Switch is EVIL! (Part 3b) – Implementing in C#

2 thoughts on “Switch is EVIL! (Part 3a)

    1. I prefer polymorphism when there is more than one method in the base implementation of which some may be overridden.

      If there is just one method and that has to be overridden, then func or delegate is easier

      Liked by 1 person

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s