loading...

Using Dictionaries to refactor

tails128 profile image Tails128 ・2 min read

About one year and a half ago, I joined an awesome team of developers which had set up a very efficient environment from which I have learned a lot.

One of the many ideas which arose in such a thriving environment is to use Dictionaries as configuration files. In order to explain what I mean, and let's start from some bad code:

switch(foo.fooType) {
  case fooType.a: {
    bar(anEnum.aValue, foo, true);
  }
  case fooType.b: {
    bar(anEnum.bValue, foo, true);
  }
  case fooType.c: {
    bar(anEnum.cValue, foo, true);
  }
  default: {
    throw new ArgumentOutOfRangeException();
  }
}

Just by looking at this code, it looks like it is very complex: in the switch we are calling a function depending on foo... but this is not true!
What is actually happening is that we are just configuring the first parameter (anEnum).

Let's fix this

anEnum myValue;
switch(foo.fooType) {
  case fooType.a: {
    myValue = anEnum.aValue
  }
  case fooType.b: {
    myValue = anEnum.bValue
  }
  case fooType.c: {
    myValue = anEnum.cValue
  }
  default: {
    throw new ArgumentOutOfRangeException();
  }
}

bar(myValue, foo, true);

This surely looks more understandable: it is immediate to see that we are not calling different functions, but we are just using a different value for myValue... but we can improve it a bit more with the use of a Dictionary.

fooConfigurator.cs:

public static Dictionary<fooType, anEnum> fooConfigurator = new Dictionary<fooType, anEnum>() {
  { fooType.a, anEnum.aValue },
  { fooType.b, anEnum.bValue },
  { fooType.c, anEnum.cValue },
}

ourFile.cs

if(!fooConfigurator.Contains(foo.fooType){
  throw new ArgumentOutOfRangeException();  
}
anEnum myValue = fooConfigurator.get(foo.fooType);
bar(myValue, foo, true);

This allows for some benefits in our code:

  1. O(1) access time instead of O(n) if you are using interpreted languages (partially compiled languages as java or c# and compiled languages usually adopt access tables, making it already O(1)... compilers are awesome!)
  2. The code is more readable: we can clearly see we just configure myValue depending on foo.fooType, and nothing else.
  3. This allows for simple configuration by updating our dictionary.

Can we do more with dictionaries?

Sure!
The cool thing about using Dictionaries as configuration files is that, if you use it with care, you can also pass functions or multiple parameters (just use objects) with a dictionary, allowing for a lot of flexibility!

What do you think about this approach? Let me know in the comments!

Posted on May 18 by:

tails128 profile

Tails128

@tails128

I am a dev from Italy, currently working in the videogames field in Germany! Like: photos, videogames, learning!

Discussion

markdown guide