← Flutter & Dart

Dart avanzado

¿Qué tipos de constructores existen en Dart (por defecto, nombrados, `factory`) y para qué sirve cada uno?

Ver respuesta — intenta responderla en voz alta primero

Dart tiene el constructor por defecto (el que lleva el nombre de la clase), constructores nombrados (para tener varias formas de crear el objeto) y el constructor factory (que puede decidir qué instancia devolver, incluso una ya existente). Además hay azúcar sintáctico para asignar propiedades directo desde los parámetros.

  • Constructor por defecto: el clásico. Dart permite abreviar la asignación con this.propiedad en los parámetros.
  • Constructor nombrado (Clase.nombre()): útil para crear el objeto de distintas maneras (por ejemplo, Punto.origen() o Color.fromHex()).
  • factory: no está obligado a crear una instancia nueva. Puede devolver una cacheada, una subclase, o construir a partir de otra fuente. Se usa mucho en patrones singleton y en fromJson.
  • Lista de inicialización (: campo = valor): asigna campos final antes de que corra el cuerpo del constructor.
class Punto {
  final double x;
  final double y;

  // Constructor por defecto con azúcar sintáctico
  Punto(this.x, this.y);

  // Constructor nombrado
  Punto.origen()
      : x = 0,
        y = 0;

  // Factory: decide qué devolver
  factory Punto.desdeMapa(Map<String, double> mapa) {
    return Punto(mapa["x"] ?? 0, mapa["y"] ?? 0);
  }

  @override
  String toString() => "Punto($x, $y)";
}

void main() {
  print(Punto(3, 4)); // Punto(3.0, 4.0)
  print(Punto.origen()); // Punto(0.0, 0.0)
  print(Punto.desdeMapa({"x": 1, "y": 2})); // Punto(1.0, 2.0)
}

Confundir un constructor normal con un factory. Un constructor normal siempre crea una instancia nueva y no puede tener return. Un factory debe tener un return y puede devolver una instancia ya existente. Intentar poner return en un constructor normal es un error clásico.

"Dart tiene el constructor por defecto, que puede abreviar la asignación con this.x en los parámetros; constructores nombrados como Punto.origen() para tener varias formas de crear el objeto; y el constructor factory, que a diferencia de uno normal no está obligado a crear una instancia nueva: puede devolver una cacheada o construir desde un JSON. Por eso factory es común en singletons y en los fromJson de los modelos."

Reto rápido

¿Por qué se suele usar factory para implementar un singleton?

Ver respuesta

Porque un factory puede devolver siempre la misma instancia en lugar de crear una nueva. Guardas una instancia estática privada y el factory la retorna cada vez:

class Config {
  static final Config _instancia = Config._interno();
  factory Config() => _instancia;
  Config._interno();
}

Cada Config() devuelve el mismo objeto.