Clases invocables
Parte de la sección Programación Orientada a Objetos del Journey de Dart de Coddy — lección 84 de 110.
En Dart, puedes hacer que las instancias de una clase sean invocables como funciones implementando el método call(). Esto te permite usar un objeto con la sintaxis de llamada a función - usando paréntesis directamente sobre la instancia.
class Multiplier {
final int factor;
Multiplier(this.factor);
int call(int value) {
return value * factor;
}
}
void main() {
var double = Multiplier(2);
var triple = Multiplier(3);
print(double(5)); // 10 - llamando al objeto como una función
print(triple(5)); // 15
}Cuando escribes double(5), Dart invoca automáticamente el método call() con 5 como argumento. El objeto se comporta como una función mientras mantiene su estado (el campo factor).
El método call() puede tener cualquier firma: múltiples parámetros, parámetros opcionales o incluso devolver diferentes tipos:
class Greeter {
final String greeting;
Greeter(this.greeting);
String call(String name, {String punctuation = '!'}) {
return '$greeting, $name$punctuation';
}
}
void main() {
var hello = Greeter('Hello');
print(hello('Alice')); // Hello, Alice!
print(hello('Bob', punctuation: '.')); // Hello, Bob.
}Las clases invocables son útiles cuando necesitas un comportamiento similar al de una función combinado con estado o configuración. Se utilizan comúnmente para crear operaciones reutilizables, validadores o transformaciones que necesitan recordar ajustes entre llamadas.
Desafío
Fácil¡Vamos a construir un sistema formateador de texto utilizando clases llamables (callable classes)! Crearás objetos que pueden ser llamados como funciones para transformar texto de diferentes maneras, manteniendo sus propios ajustes de configuración.
Organizarás tu código en dos archivos:
formatters.dart: Crea dos clases llamables que transformen texto:- Una clase
Wrapperque envuelva el texto con un prefijo y un sufijo. Debe almacenar unString prefixy unString suffix, y cuando se llame con un parámetroString text, debe devolver el texto envuelto entre el prefijo y el sufijo. - Una clase
Repeaterque repita el texto un cierto número de veces. Debe almacenar un valorint times, y cuando se llame con un parámetroString text, debe devolver el texto repetido esa cantidad de veces con un espacio entre cada repetición.
- Una clase
main.dart: Importa tus formateadores y demuestra cómo funcionan las clases llamables:- Crea un
Wrappercon el prefijo"["y el sufijo"]" - Crea otro
Wrappercon el prefijo"***"y el sufijo"***" - Crea un
Repeaterque repita 3 veces - Llama al primer wrapper con
"Hello"e imprime el resultado - Llama al segundo wrapper con
"Important"e imprime el resultado - Llama al repeater con
"Go"e imprime el resultado - Finalmente, combínalos: llama al primer wrapper con el resultado de llamar al repeater con
"Dart", e imprime el resultado
- Crea un
¡Observa cómo cada objeto formateador recuerda su configuración y puede ser llamado directamente con paréntesis, igual que una función!
Salida esperada:
[Hello]
***Important***
Go Go Go
[Dart Dart Dart]Hoja de referencia
Las clases pueden hacerse invocables como funciones implementando el método call():
class Multiplier {
final int factor;
Multiplier(this.factor);
int call(int value) {
return value * factor;
}
}
void main() {
var double = Multiplier(2);
print(double(5)); // 10 - calling the object like a function
}El método call() puede tener cualquier firma con múltiples parámetros, parámetros opcionales o diferentes tipos de retorno:
class Greeter {
final String greeting;
Greeter(this.greeting);
String call(String name, {String punctuation = '!'}) {
return '$greeting, $name$punctuation';
}
}
void main() {
var hello = Greeter('Hello');
print(hello('Alice')); // Hello, Alice!
print(hello('Bob', punctuation: '.')); // Hello, Bob.
}Las clases invocables son útiles para crear un comportamiento similar al de una función combinado con estado o configuración.
Pruébalo tú mismo
import 'formatters.dart';
void main() {
// TODO: Crear un Wrapper con el prefijo "[" y el sufijo "]"
// TODO: Crear otro Wrapper con el prefijo "***" y el sufijo "***"
// TODO: Crear un Repeater que se repita 3 veces
// TODO: Llamar al primer wrapper con "Hello" e imprimir el resultado
// TODO: Llamar al segundo wrapper con "Important" e imprimir el resultado
// TODO: Llamar al repeater con "Go" e imprimir el resultado
// TODO: Combinarlos: llamar al primer wrapper con el resultado de
// llamar al repeater con "Dart", e imprimir el resultado
}
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
1Fundamentos de POO
Archivos externosLibrerías e importacionesIntroducción a la POOClases vs. ObjetosLa palabra clave thisMétodosVariables de instanciaConceptos básicos de constructoresResumen - Calculadora sencilla4Seguridad de nulos
Introducción a la seguridad de nulosNulables vs No nulablesLos operadores ? y !Palabra clave Late y Null SafetyOperadores Null-awareNull Safety en clasesResumen - Sistema de perfil de usuario7Clases abstractas e interfaces
Clases abstractasMétodos abstractosInterfaces en DartInterfaces implícitasImplementar vs. ExtenderInterfaces múltiplesRepaso - Calculadora de figuras10Colecciones y Genéricos
Visión general de List, Set y MapColecciones con seguridad de tiposClases genéricasMétodos genéricosRestricciones genéricasIterable e IteratorResumen - Almacenamiento genérico13Conceptos avanzados de POO
Composición vs. HerenciaMétodos de extensiónClases invocablesClases selladas (Dart 3)Records (Dart 3)Patrones y coincidencia (3.0)Enums con métodos2Constructores en Dart
Constructor por defectoConstructores nombradosListas de inicializaciónConstructores constantesConstructores de fábricaConstructores de redireccionamientoResumen - Constructor de formas5Encapsulamiento
Miembros públicos vs. privadosLa convención del prefijo _Privacidad a nivel de libreríaProfundidad en Getters y SettersOcultamiento de informaciónResumen - Registros de estudiantes8Mixins
Introducción a los MixinsCreación de MixinsUso de múltiples MixinsPalabra clave on en MixinsMixin vs HerenciaMixin vs InterfazResumen - Sistema Animal11Métodos especiales
Sobrescritura de toString()Sobrescritura de hashCode y ==Interfaz ComparableMétodo call()Sobrescritura de noSuchMethodResumen - Colección personalizada14Patrones de diseño Parte 1
Introducción a los patrones de diseñoPatrón SingletonPatrón FactoryPatrón ObserverPatrón Strategy3Propiedades de clase
Miembros de instancia vs. estáticosCampos Final y ConstVariables LateMétodos y campos estáticosGetters y SettersResumen - Gestor de cuentas bancarias6Herencia
Herencia básicaLa palabra clave superSobrescritura de métodosLa anotación @overrideLa palabra clave final en clasesConstructores y herenciaResumen - Jerarquía de empleados9Polimorfismo
Fundamentos del polimorfismoPolimorfismo mediante interfacesComprobación de tipos en tiempo de ejecuciónLos operadores is y asPalabra clave covariantResumen - Procesador de pagos12POO Asíncrona
Futures y async/awaitFundamentos de StreamsStream ControllersConstructores asíncronosAsincronía en métodos de claseRepaso - Data Fetcher15Patrones de diseño Parte 2
Patrón CommandPatrón AdapterPatrón DecoratorPatrón Template MethodPatrón StatePatrón CompositePatrón Repository