Patrón Observer
Parte de la sección Programación Orientada a Objetos del Journey de Dart de Coddy. Lección 92 de 110.
El patrón Observer establece una relación de uno a muchos entre objetos: cuando un objeto (el sujeto) cambia de estado, todos sus dependientes (observadores) reciben una notificación automáticamente. Esto es perfecto para situaciones como actualizaciones de la interfaz de usuario, sistemas de eventos o cualquier caso en el que varias partes de tu aplicación deban reaccionar a los cambios.
El patrón implica dos roles clave: un sujeto que mantiene una lista de observadores y les notifica los cambios, y observadores que se registran y responden a las actualizaciones:
abstract class Observer {
void update(String message);
}
class NewsAgency {
final List<Observer> _observers = [];
String _latestNews = '';
void subscribe(Observer observer) {
_observers.add(observer);
}
void unsubscribe(Observer observer) {
_observers.remove(observer);
}
void publishNews(String news) {
_latestNews = news;
for (var observer in _observers) {
observer.update(_latestNews);
}
}
}
class NewsChannel implements Observer {
final String name;
NewsChannel(this.name);
@override
void update(String message) {
print('$name received: $message');
}
}
void main() {
var agency = NewsAgency();
var cnn = NewsChannel('CNN');
var bbc = NewsChannel('BBC');
agency.subscribe(cnn);
agency.subscribe(bbc);
agency.publishNews('Breaking news!');
// CNN received: Breaking news!
// BBC received: Breaking news!
}Cuando se llama a publishNews, la agencia itera a través de todos los observadores suscritos y llama a su método update. Los observadores pueden suscribirse o cancelar su suscripción en cualquier momento, lo que hace que el sistema sea flexible y esté débilmente acoplado: el sujeto no necesita conocer los tipos específicos de sus observadores.
Desafío
Fácil¡Construyamos un sistema de alertas de precios de acciones usando el patrón Observer! Crearás un sistema en el que un marcador de cotizaciones notifica a varios inversores cada vez que cambia el precio, lo que permite que cada inversor reaccione a las actualizaciones del mercado a su manera.
Organizarás tu código en dos archivos:
stock_system.dart: Crea aquí tu sistema de observadores:- Una clase abstracta
Investorcon un métodovoid onPriceChange(String stockName, double price) - Una clase
DayTraderque implementaInvestor. Tiene un camponamey su métodoonPriceChangeimprime:[name] sees [stockName] at $[price] - Making quick trade! - Una clase
LongTermInvestorque implementaInvestor. Tiene un camponamey su métodoonPriceChangeimprime:[name] notes [stockName] at $[price] - Holding steady. - Una clase
StockTicker(el sujeto) con:- Un campo
String stockName - Una lista privada para almacenar a los inversores suscritos
- Un método
subscribe(Investor investor)para añadir un inversor - Un método
unsubscribe(Investor investor)para eliminar un inversor - Un método
updatePrice(double newPrice)que notifica a todos los inversores suscritos del nuevo precio
- Un campo
- Una clase abstracta
main.dart: Importa tu sistema de acciones y demuestra el patrón Observer en funcionamiento:- Crea un
StockTickerpara una acción llamadaDART - Crea un
DayTraderllamadoAlicey unLongTermInvestorllamadoBob - Suscribe a ambos inversores al marcador de cotizaciones
- Actualiza el precio a
150.50(ambos inversores deben recibir una notificación) - Imprime una línea vacía
- Cancela la suscripción de Alice al marcador de cotizaciones
- Actualiza el precio a
155.75(ahora solo Bob debe recibir una notificación)
- Crea un
Esto demuestra cómo el patrón Observer crea un sistema débilmente acoplado: StockTicker no necesita saber si está notificando a operadores intradía o a inversores a largo plazo; simplemente llama a onPriceChange en quienquiera que esté suscrito.
Salida esperada:
Alice sees DART at $150.5 - Making quick trade!
Bob notes DART at $150.5 - Holding steady.
Bob notes DART at $155.75 - Holding steady.Pruébalo tú mismo
import 'stock_system.dart';
void main() {
// TODO: Crear un StockTicker para una acción llamada 'DART'
// TODO: Crear un DayTrader llamado 'Alice'
// TODO: Crear un LongTermInvestor llamado 'Bob'
// TODO: Suscribir a ambos inversores al ticker
// TODO: Actualizar el precio a 150.50 (ambos inversores deben ser notificados)
// TODO: Imprimir una línea vacía
// TODO: Cancelar la suscripción de Alice del ticker
// TODO: Actualizar el precio a 155.75 (ahora solo Bob debe ser notificado)
}
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