A Constructor is a special type of method that is used to initialize new instances of a class.
That is, when we create an instance of a class, the Constructor is a method that automatically executes during creation (generally to set the initial state of the object).
Why would we want to execute a method when creating an object? Well, generally to
- Initialize variables and internal state
- Perform certain validations
- Or to do absolutely nothing 🤷
Because yes, many times what we want to do is absolutely nothing. Not all objects need us to do “something” in their constructor (in fact, most do not need it).
Finally, most languages allow defining multiple constructors for a class, each with different parameters. This is called constructor overloading.
Examples of constructors in different languages
Generally, the Constructor is a method that:
- Name: Generally, it has the same name as the class it belongs to.
- Parameters: It receives parameters.
- No Return Type: Unlike other methods, constructors do not have a return type, not even
void
.
Let’s see what a constructor looks like in different programming languages, and how we would use it to create instances of a class Person
.
public class Persona {
public string nombre;
public int edad;
// Constructor
public Persona(string nombre, int edad) {
this.nombre = nombre;
this.edad = edad;
}
public void Presentarse() {
Console.WriteLine($"Hola, mi nombre es {nombre} y tengo {edad} años.");
}
}
// Crear una instancia de la clase Persona
Persona personaLuis = new Persona("Luis", 30);
personaLuis.Presentarse();
// Crear otra instancia de la clase Persona
Persona personaMaria = new Persona("Maria", 20);
personaMaria.Presentarse();
class Persona {
public:
string nombre;
int edad;
// Constructor
Persona(string nombre, int edad) {
this->nombre = nombre;
this->edad = edad;
}
void presentarse() {
cout << "Hola, mi nombre es " << nombre << " y tengo " << edad << " años." << endl;
}
};
// Crear una instancia de la clase Persona
Persona personaLuis("Luis", 30);
personaLuis.presentarse();
// Crear otra instancia de la clase Persona
Persona personaMaria("Maria", 20);
personaMaria.presentarse();
class Persona {
constructor(nombre, edad) {
this.nombre = nombre;
this.edad = edad;
}
presentarse() {
console.log(`Hola, mi nombre es ${this.nombre} y tengo ${this.edad} años.`);
}
}
// Crear una instancia de la clase Persona
const personaLuis = new Persona("Luis", 30);
personaLuis.presentarse();
// Crear otra instancia de la clase Persona
const personaMaria = new Persona("Maria", 20);
personaMaria.presentarse();
class Persona:
def __init__(self, nombre, edad):
self.nombre = nombre
self.edad = edad
def presentarse(self):
print(f"Hola, mi nombre es {self.nombre} y tengo {self.edad} años.")
# Crear una instancia de la clase Persona
personaLuis = Persona("Luis", 30)
personaLuis.presentarse()
# Crear otra instancia de la clase Persona
personaMaria = Persona("Maria", 20)
personaMaria.presentarse()
In the previous examples, we see that the constructor of the Persona
class initializes the instance variables nombre
and edad
.
On the other hand, we see how the constructor is used when we create an instance of the class for Luis with age 30, and Maria with age 20.
Destructors
Just as constructors handle initialization, Destructors (or finalizers) are special methods that execute when an object is destroyed or freed.
Destructors are used to perform any necessary cleanup before the object is removed from memory (generally, mainly to free resources, such as closing files or database connections).
Examples of Destructors in different languages
Let’s see how to create Destructors or finalizers in different programming languages,
In C#, destructors (~Persona
) are automatically called when the object is about to be destroyed, allowing for resource release.
public class Persona {
public string nombre;
public int edad;
// Constructor
public Persona(string nombre, int edad) {
this.nombre = nombre;
this.edad = edad;
}
// Destructor
~Persona() {
Console.WriteLine($"El objeto Persona {nombre} ha sido destruido.");
}
}
Similarly, in C++, the destructor (~Persona
) is also declared similarly.
class Persona {
public:
string nombre;
int edad;
// Constructor
Persona(string nombre, int edad) {
this->nombre = nombre;
this->edad = edad;
}
// Destructor
~Persona() {
cout << "El objeto Persona " << nombre << " ha sido destruido." << endl;
}
};
In JavaScript, there is no concept of destructors. However, we can use certain patterns to clean up resources if necessary.
class Persona {
constructor(nombre, edad) {
this.nombre = nombre;
this.edad = edad;
}
presentarse() {
console.log(`Hola, mi nombre es ${this.nombre} y tengo ${this.edad} años.`);
}
// Method to manually release resources
liberarRecursos() {
console.log(`Recursos de ${this.nombre} han sido liberados.`);
}
}
// Example of use
const personaLuis = new Persona("Luis", 30);
personaLuis.presentarse();
personaLuis.liberarRecursos();
In Python, the destructor (__del__
) is called when the object is collected by the garbage collector, or when we force its destruction using del
.
class Persona:
def __init__(self, nombre, edad):
self.nombre = nombre
self.edad = edad
def __del__(self):
print(f"El objeto Persona {self.nombre} ha sido destruido.")
def presentarse(self):
print(f"Hola, mi nombre es {self.nombre} y tengo {self.edad} años.")
# Example of use
personaLuis = Persona("Luis", 30)
personaLuis.presentarse()
del personaLuis # Force the destruction of the object
Best practices Tips
When to use a constructor
Throughout your life as a programmer, you will probably go through a love-hate relationship with constructors. Especially regarding when you need to use a Constructor, and when it’s better to use other mechanisms.
You will probably use them shyly at first. Then you will be tempted to use them for everything. And in the end, you will start to not use them at all and prefer other ways to initialize objects like the Factory Pattern.
In any case, the less you use constructors the better (controversial 😮). It’s preferable to have simple objects that contain as little logic as possible and use them as data containers.
For me, when does it make sense to use a constructor? When you are initializing variables that the object needs to function and without that variable, it doesn’t even make sense for it to exist.
For example, let’s imagine you have a Repository
object, whose function is to save data in a database. For that, it needs a connection to a database.
public class Repository
{
DbConnection _connection;
Repository(DbConnection connection)
{
_connection = connection;
}
// more methods
}
It is indisputable that Repository
has a connection. Without it, any call to that object will result in an error. Literally, the Repository
object does not make sense to exist without a connection.
In that case, it is logical that Repository
receives the connection in the constructor. Because it is the minimum necessary for it to work.
But what about a Car
object? We might think that the minimum a Car needs is its license plate
.
public class Coche
{
string _matricula;
Coche(string matricula)
{
_matricula = matricula;
}
}
But what if I can have cars in a dealership that do not have a license plate yet? Should we take the chassis number? And what if what I am programming is a Parking lot, and I don’t have chassis numbers?
That is, there is no single answer. What is necessary, and what should go as a constructor, depends on your object model.
That is part of the design process of your program’s object model. As advice, do not use a constructor unless you are very clear about it.
On the other hand, when you need / decide to use a constructor, always follow these guidelines:
- As simple as possible
- It should never be a long process (like reading from a database, a file, etc)
- They should be as independent as possible from the rest of the classes
When to use a destructor
On the other hand, Destructors are less open to debate. If during the use of a class you are using a resource, you must ensure that it is released when destroying the instance. Here, there is not much doubt about when to use it; this must always be done.