Patrón Command
Parte de la sección Programación Orientada a Objetos del Journey de Dart de Coddy. Lección 94 de 110.
El patrón Command encapsula una solicitud como un objeto, lo que te permite parametrizar los clientes con distintas solicitudes, poner operaciones en cola o admitir la funcionalidad de deshacer. En lugar de llamar directamente a un método, envuelves la acción en un objeto de comando que se puede almacenar, pasar de un lado a otro o ejecutar más tarde.
El patrón implica tres componentes clave: una interfaz Command con un método execute, Comandos concretos que implementan acciones específicas y un Receptor que realiza el trabajo real. Un Invocador opcional activa los comandos sin saber qué hacen:
abstract class Command {
void execute();
}
class Light {
void turnOn() => print('Light is ON');
void turnOff() => print('Light is OFF');
}
class TurnOnCommand implements Command {
final Light light;
TurnOnCommand(this.light);
@override
void execute() => light.turnOn();
}
class TurnOffCommand implements Command {
final Light light;
TurnOffCommand(this.light);
@override
void execute() => light.turnOff();
}
class RemoteControl {
Command? _command;
void setCommand(Command command) {
_command = command;
}
void pressButton() {
_command?.execute();
}
}
void main() {
var light = Light();
var remote = RemoteControl();
remote.setCommand(TurnOnCommand(light));
remote.pressButton(); // La luz está ENCENDIDA
remote.setCommand(TurnOffCommand(light));
remote.pressButton(); // La luz está APAGADA
}El RemoteControl no sabe nada sobre las luces; simplemente ejecuta cualquier comando que se le asigne. Este desacoplamiento facilita añadir nuevos comandos sin modificar el invocador. El patrón Command es ideal para implementar sistemas de deshacer/rehacer, colas de tareas o grabación de macros cuando necesitas tratar las acciones como objetos de primera clase.
Desafío
Fácil¡Construyamos un sistema de comandos para un editor de texto usando el patrón Command! Crearás un sistema que encapsula las operaciones de texto como objetos de comando, lo que permite que un editor ejecute diferentes acciones sin conocer los detalles de cada operación. Este es un caso de uso clásico del patrón Command: piensa en él como un sistema de deshacer/rehacer en el que cada acción se almacena como un objeto.
Organizarás tu código en dos archivos:
commands.dart: Crea aquí tu sistema de comandos. Comienza con una clase abstractaCommandque declare un métodoexecute(). Después, crea una claseTextDocument(el receptor) que contenga un campoString content(inicialmente vacío) y tenga tres métodos:append(String text): añade texto al final del contenidoclear(): establece el contenido como una cadena vacíashow(): imprimeDocument: [content]
TextDocument:AppendCommand: recibe un documento y texto en su constructor, y añade el texto cuando se ejecutaClearCommand: recibe un documento en su constructor y lo borra cuando se ejecutaShowCommand: recibe un documento en su constructor y muestra su contenido cuando se ejecuta
TextEditor(el invocador) que almacene una lista de comandos. Debe tener un métodoaddCommand(Command command)para poner comandos en cola, y un métodorunAll()que ejecute todos los comandos en cola en orden.main.dart: Importa tu archivo de comandos y demuestra el patrón Command. Crea unTextDocumenty unTextEditor. Pon en cola los siguientes comandos en orden: añadirHello, añadirWorld, mostrar el documento, añadir!, mostrarlo de nuevo, borrar el documento y mostrarlo una última vez. Después, ejecuta todos los comandos en cola.
Observa que TextEditor no sabe nada sobre añadir, borrar o mostrar; simplemente ejecuta los comandos que recibe. ¡Este desacoplamiento es la esencia del patrón Command!
Salida esperada:
Document: Hello World
Document: Hello World!
Document: Pruébalo tú mismo
import 'commands.dart';
void main() {
// TODO: Crear una instancia de TextDocument
// TODO: Crear una instancia de TextEditor
// TODO: Poner en cola los siguientes comandos en orden:
// 1. Añadir "Hello"
// 2. Añadir " World"
// 3. Mostrar el documento
// 4. Añadir "!"
// 5. Mostrar el documento de nuevo
// 6. Limpiar el documento
// 7. Mostrar el documento una última vez
// TODO: Ejecutar todos los comandos en cola
}
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érico2Constructores 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 RepositoryPractica por tu cuenta: Compilador de Dart online