Avoiding endless switch-case structures with classes

Tags:

Imagine the following: you have some form elements that need to render themselves. You have saved them in a database, as your users must be able to modify the forms. You have a bunch of different kinds of elements: a text field, a longer textarea field, maybe a field used for entering dates.

How would you determine, which kind of a field your code needs to render? The simple choice would be to put them in a switch block, which looks at the type of the element, and maybe calls some method based on that.

But what if you need to add a new element type? What if you need to add 10 new element types? The switch will get very long and that’s not good for readability of the code. But with some smart use of classes and polymorphism, we can easily solve this problem

A simple approach

Instead of using the switch block to decide what we want to render, we can instead load classes dynamically to do the job.

We first define an interface for them. Our example is going to be the form element, but you can use this approach with anything else too. So we will define a FormElement interface, which contains methods setData and render – setData will be used to tell the implementing class the parameters it needs to work with, such as the field’s value, and the render method will, surprisingly, be used to get the actual html code for the element.

Now, how do we choose which class to use without a switch? We can use a naming scheme: for example, FormType. Now we can easily create a new instance of a class based on its type:
//Let's assume $data contains things like the form element's type etc.
$className = 'Form' . ucfirst($data['type']);
 
$element = new $className;
$element->setData($data);
 
$html = $element->render();

Much nicer than a long, long switch block! And now, if we want to add a new element type, we won’t even need to modify this code as long as we stick to our naming scheme. If we used a switch, we would need to add a new case for each new element we add.

Adding to the example: using a factory

We could improve the example slightly. We can do this by introducing a factory class, which returns instances of the form element.

The advantage of this is that if you ever need to modify your naming scheme or how the element class is constructed, you will not have to touch the code that’s using them. This is even better in cases where you have more than one place where you need to create a form element: even though our code to create the new class is pretty short, it would mean we have the logic duplicated.

One additional advantage of using a factory is that sometimes you may want to have more than one “group” of items. These groups may have different ways they are created, so having a factory do this would make it easier to use.

The factory would be relatively simple: it needs a method which will return an instance of a specific kind of an element.

class FormElementFactory {
  public function createElement($type) {
    $className = 'Form' . ucfirst($type);
    $element = new $className;
    return $element;
  }
}

Conclusion

Using a switch structure to choose between different ways of proceeding is often a simple and quick to implement way to solve the problem. However, when you start to need more than just a handful of cases, the code can often end up being difficult to read and manage.

Using classes as illustrated in the post, it’s quite simple to achieve the same result. This does add a small step of complexity into the application, and some more files to include, but it’s often worth it.

By using a factory class to create the different types of classes you can enhance the result some more, but if your use case is simple it may be worth considering if a factory is necessary – it may not be useful in every case.

ps: I used some more model diagrams in this than I usually do. Let me know if you find them helpful =)