We all have been through situations, where we had to create classes with multiple constructors or constructor with a lot of dependencies (parameters). These classes tend to get bloated quickly with the over used constructor methods and too many parameters and starts messing with the default properties values. Whenever you find yourself into this situation you; my friend; have been trapped by a notorious anti-pattern called Telescopic Constructors or, Telescopic Initializers. The initial intention of this pattern was to simplify the process of working with classes with a lot of initializer parameters.
In this blogpost, I am going to discuss how we get trapped by the telescopic constructor. Let us take a look at the following example code snippet:
We all love biriaynis, right? If not, what are you doing with your life man! 😱 Go have some biriyani first!
Jokes apart, here we have a restaurant that sells biriyanis. The
Biriyani class defines an initializer with three parameters. This requires calling classes to know what the default values will be for the parameters and set them every time:
var biriyani = Biriyani(count: 1, size: .medium, spiceRange: .extraHot)
Though we are forcing the
Restaurant class to set all parameters of the
Biriyani class every time, most customers won’t be giving a lot of customized orders, making it possible to use some default values for the class. For example, most customers will only order a single medium sized dish with only the spice range varied.
So we try to improve our
Biriyani class’ initialization usability by using telescoping constructors. This pattern tells us to create convenience initializers that will provide default values for our orders.
Each convenience initializer removes an additional parameter and calls the original initializer with a default value. It allows other classes to create it without knowing the default values for the parameters:
var biriyaniOrder1 = Biriyani(size: .medium, spiceRange: .extraHot) var biriyaniOrder2 = Biriyani(spiceRange: .extraHot)
Savvy, right? So far so good. Now what if the restaurant adds another parameter to the
Biriyani class called
BiriyaniType? We’ll have to add some extra convenience initializers to support more custom orders.
Now the customers have a lot of options to order their biriyanis:
var biriyaniOrder1 = Biriyani(size: .medium, spiceRange: .hot, type: .veg) var biriyaniOrder2 = Biriyani(spiceRange: .extraHot, type: .veg) var biriyaniOrder3 = Biriyani(spiceRange: .extraHot) var biriyaniOrder4 = Biriyani(type: .veg)
Just by increasing an extra parameter
BiriyaniType, we’ve been forced the
Biriyani class to add two more constructors to the class. Now consider what if the restaurant has to add more parameters like this? What will happen? This is the pitfall of using Telescoping Constructors. It is considered an Anti-pattern because, it results a large number of initializers that are hard to read and maintain.
Fortunately in swift we can provide default values to parameters:
The default values for the parameters are used whenever the
Restaurant class wants to create a
Biriyani by omitting them. This is the benefit of defining the default values within the
Biriyani class without the necessity of defining a permutation of initializers.
I am going discuss another way to solve the telescoping initializers in my next post using Builder Pattern.
I hope you have enjoyed and understood the pitfalls of this particular anti-pattern. Any questions, feedbacks or if you think I have some improvements to do, feel free to comment and let me know!
Happy coding! 😁