In dart, constructors play a similar role, but have several variations that do not exist in most programming languages. This article will go over the different use cases and examples of constructors.
In all of the examples for this article, we will be using the following class:
class Car {
String make;
String model;
String yearMade;
bool hasABS;
}
How to Get Started with Constructors in Dart
If you do not specify any constructor in Dart, it will create a default constructor for you.
This does not mean that you will see a default constructor generated in your class. Instead, when creating a new instance of your class, this constructor will be called. It will have no arguments and will call the constructor of the super class, with no arguments as well.
To declare a constructor in your class, you can do the following:
class Car {
String make;
String model;
String yearMade;
bool hasABS;
Car(String make, String model, int year, bool hasABS) {
this.make = make;
this.model = model;
this.yearMade = year;
this.hasABS = hasABS;
}
}
As you can imagine, there must be a better way to initialize our class fields – and in Dart, there is:
class Car {
String make;
String model;
String yearMade;
bool hasABS;
Car(this.make, this.model, this.yearMade, this.hasABS);
}
The way we use above is just syntactic sugar that Dart has to simplify the assignment.
More Complex Constructor Features
In other languages, it is possible to overload your constructor. This means that you can have different constructors with the same name, but with a varying signature (or different set of arguments).
Named constructors in Dart
In Dart, this is not possible, but there is a way around it. It is called named constructors. Giving your constructors different names allows your class to have many constructors and also to better represent their use cases outside of the class.
class Car {
String make;
String model;
String yearMade;
bool hasABS;
Car(this.make, this.model, this.yearMade, this.hasABS);
Car.withoutABS(this.make, this.model, this.yearMade): hasABS = false;
}
Named Constructor Example
The constructor withoutABS initializes the instance variable hasABS to false, before the constructor body executes. This is known as an initializer list and you can initialize several variables, separated by a comma.
The most common use case for initializer lists is to initialize final fields declared by your class.
✋ Anything that is placed on the right hand side of the colon (:) has no access to this.
Factory constructors in Dart
A factory constructor is a constructor that can be used when you don't necessarily want a constructor to create a new instance of your class.
This might be useful if you hold instances of your class in memory and don't want to create a new one each time (or if the operation of creating an instance is costly).
Another use case is if you have certain logic in your constructor to initialize a final field that cannot be done in the initializer list.
class Car {
String make;
String model;
String yearMade;
bool hasABS;
factory Car.ford(String model, String yearMade, bool hasABS) {
return FordCar(model, yearMade, hasABS);
}
}
class FordCar extends Car {
FordCar(String model, String yearMade, bool hasABS): super("Ford", model, yearMade, hasABS);
}
Factory Constructor Example
Advanced Constructors in Dart
Constant constructors and redirecting constructors in Dart
Dart also allows you to create constant constructors. What does this mean exactly? If your class represents an object that will never change after its creation, you can benefit from the use of a constant constructor. You have to make sure that all your class fields are final.
class FordFocus {
static const FordFocus fordFocus = FordFocus("Ford", "Focus", "2013", true);
final String make;
final String model;
final String yearMade;
final bool hasABS;
const FordFocus(this.make, this.model, this.yearMade, this.hasABS);
}
Constant Constructor Example
When you want one constructor to call another constructor under the hood, it's referred to as redirecting constructors.
class Car {
String make;
String model;
String yearMade;
bool hasABS;
Car(this.make, this.model, this.yearMade, this.hasABS);
Car.withoutABS(this.make, this.model, this.yearMade): this(make, model, yearMade, false);
}
Redirecting Constructor Example
Wrapping up
Each of the constructors we discussed has a different purpose and use case. It is up to you to determine and understand when to use each one. Hopefully, this article gave you the necessary knowledge to do so.