Menu
Coddy logo textTech

Constructores de fábrica

Parte de la sección Programación Orientada a Objetos del Journey de Dart de Coddy — lección 14 de 110.

Un constructor de fábrica es un constructor especial que no siempre crea una nueva instancia. A diferencia de los constructores regulares, un constructor de fábrica puede devolver una instancia existente, un subtipo o incluso null (si es anulable). Se declara utilizando la palabra clave factory.

class Logger {
  static final Logger _instance = Logger._internal();
  
  // Constructor nombrado privado
  Logger._internal();
  
  // Constructor de fábrica
  factory Logger() {
    return _instance;
  }
}

Logger log1 = Logger();
Logger log2 = Logger();
print(identical(log1, log2)); // true

En este ejemplo, el constructor de fábrica siempre devuelve la misma instancia. No importa cuántas veces llames a Logger(), obtendrás el objeto idéntico. Este patrón se utiliza comúnmente para implementar singletons.

Los constructores factory se diferencian de los constructores regulares de una manera clave: no tienen acceso a this porque es posible que no creen una nueva instancia en absoluto. En su lugar, deben devolver explícitamente un objeto:

class Shape {
  factory Shape(String type) {
    if (type == 'circle') return Circle();
    if (type == 'square') return Square();
    return Rectangle();
  }
}

class Circle extends Shape { Circle() : super._(); }
class Square extends Shape { Square() : super._(); }
class Rectangle extends Shape { Rectangle() : super._(); }

Los constructores factory son útiles cuando necesitas control sobre la creación de instancias, como devolver objetos almacenados en caché, implementar pools de objetos o decidir qué subtipo instanciar basándose en los parámetros de entrada.

challenge icon

Desafío

Fácil

Vamos a construir un sistema de notificaciones que utiliza constructores de fábrica para crear diferentes tipos de notificaciones basadas en una simple entrada de cadena.

Crearás dos archivos para organizar tu código:

  • notification.dart: Define una clase Notification que sirva como base para todos los tipos de notificación. Tu clase debe tener:
    • Un campo String message
    • Un constructor nombrado privado Notification._internal que inicialice el mensaje
    • Un constructor de fábrica Notification(String type, String message) que devuelva diferentes subtipos de notificación basados en el parámetro type:
      • Si el tipo es 'email', devuelve un EmailNotification
      • Si el tipo es 'sms', devuelve un SMSNotification
      • De lo contrario, devuelve un PushNotification
    • Un método send() que imprima Sending: [message]

In el mismo archivo, crea tres subclases que extiendan Notification:

  • EmailNotification: Sobrescribe send() para imprimir Email: [message]
  • SMSNotification: Sobrescribe send() para imprimir SMS: [message]
  • PushNotification: Sobrescribe send() para imprimir Push: [message]

Cada subclase necesita un constructor que reciba un message y lo pase al padre usando super._internal(message).

  • main.dart: Importa tu clase de notificación y crea tres notificaciones usando el constructor de fábrica:
    • Una notificación de correo electrónico con el mensaje 'Welcome!'
    • Una notificación de SMS con el mensaje 'Your code is 1234'
    • Una notificación push con el mensaje 'New update available'
    Llama a send() en cada notificación en el orden indicado anteriormente.

Salida esperada:

Email: Welcome!
SMS: Your code is 1234
Push: New update available

Hoja de referencia

Un constructor de fábrica (factory constructor) es un constructor especial declarado con la palabra clave factory que no siempre crea una nueva instancia. A diferencia de los constructores regulares, puede devolver una instancia existente, un subtipo o null.

Los constructores de fábrica no tienen acceso a this y deben devolver explícitamente un objeto.

Ejemplo de patrón Singleton:

class Logger {
  static final Logger _instance = Logger._internal();
  
  Logger._internal(); // Private named constructor
  
  factory Logger() {
    return _instance; // Always returns same instance
  }
}

Logger log1 = Logger();
Logger log2 = Logger();
print(identical(log1, log2)); // true

Devolver diferentes subtipos:

class Shape {
  factory Shape(String type) {
    if (type == 'circle') return Circle();
    if (type == 'square') return Square();
    return Rectangle();
  }
}

class Circle extends Shape { Circle() : super._(); }
class Square extends Shape { Square() : super._(); }
class Rectangle extends Shape { Rectangle() : super._(); }

Los constructores de fábrica son útiles para controlar la creación de instancias, como devolver objetos almacenados en caché, implementar pools de objetos o decidir qué subtipo instanciar en función de los parámetros de entrada.

Pruébalo tú mismo

import 'notification.dart';

void main() {
  // TODO: Crear una notificación por correo electrónico con el mensaje 'Welcome!'
  
  // TODO: Crear una notificación por SMS con el mensaje 'Your code is 1234'
  
  // TODO: Crear una notificación push con el mensaje 'New update available'
  
  // TODO: Llamar a send() en cada notificación en orden
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación Orientada a Objetos