# data[].attributes.body
El cambio de responsabilidad implica la transferencia de tareas específicas de un componente a otro, lo que permite que cada clase o módulo del sistema cumpla con una única responsabilidad, mejorando la modularidad y la mantenibilidad del software. [1]

# data[].attributes.body
Está profundamente vinculado con los siguientes principios SOLID:

# data[].attributes.headline
Principio de responsabilidad única (SRP) 

# data[].attributes.subject
Principio de responsabilidad única (SRP) 

# data[].attributes.body
A través este, las clases mantienen una única responsabilidad, evitando la sobrecarga y favoreciendo la claridad del código.

# data[].attributes.body
También promueve el OCP, permitiendo que las clases sean extendibles sin modificar su comportamiento interno.

# data[].attributes.headline
3. Patrones de diseño que aplican el cambio de responsabilidad:

# data[].attributes.subject
3. Patrones de diseño que aplican el cambio de responsabilidad:

# data[].attributes.body
Patrón de Delegación

Consiste en que un objeto delega la responsabilidad de ejecutar una operación a otro objeto. Es esencial para implementar la separación de responsabilidades, ya que permite que un objeto principal gestione tareas sin tener que ejecutarlas por sí mismo.

# data[].attributes.body
Imagina que en una oficina, el gerente de un proyecto tiene varias responsabilidades, como preparar informes, coordinar reuniones y gestionar presupuestos. Sin embargo, en lugar de hacer todo por sí mismo, el gerente delegará estas tareas a diferentes miembros de su equipo, quienes tienen habilidades especializadas para llevarlas a cabo.

Gerente: Actúa como el "controlador" que tiene el objetivo general.

Especialista en informes: Se encarga de la redacción y presentación de los informes.

Coordinador de reuniones: Organiza y coordina las reuniones necesarias.

Encargado de finanzas: Gestiona y revisa los presupuestos del proyecto.

# data[].attributes.body
Patrón Estrategia

Permite que un objeto cambie su comportamiento en tiempo de ejecución, delegando la responsabilidad de un algoritmo específico a una clase concreta de estrategia.

# data[].attributes.body
Patrón Cadena de Responsabilidad

Permite que una solicitud pase a través de una cadena de manejadores. Cada manejador tiene la oportunidad de procesar la solicitud o pasarla al siguiente en la cadena. Es útil cuando se necesita delegar la responsabilidad del manejo de una tarea a múltiples objetos.

# data[].attributes.body
Patrón Comando

Encapsula una solicitud como un objeto, permitiendo la delegación del procesamiento de esa solicitud a diferentes manejadores o receptores.

# data[].attributes.headline
4. Beneficios del cambio de responsabilidad

# data[].attributes.subject
4. Beneficios del cambio de responsabilidad

# data[].attributes.body
Tiene varios beneficios importantes:

# data[].attributes.body
Al distribuir las responsabilidades adecuadamente, se obtiene un sistema modular donde las clases tienen funciones específicas, lo que facilita la mantenibilidad del código.

# data[].attributes.body
Las clases especializadas permiten que partes del código se puedan reutilizar en otros contextos, promoviendo la eficiencia en el desarrollo.

# data[].attributes.body
Permite que el sistema sea más flexible, ya que los cambios pueden implementarse sin afectar otros componentes.

# data[].attributes.body
Java: Implementación del Patrón Estrategia

# data[].attributes.body
El patrón estrategia se implementa creando una interfaz común para los algoritmos (estrategias) y permitiendo que la clase principal delegue el comportamiento a diferentes implementaciones de la estrategia. Esto facilita la extensión del comportamiento sin modificar el código existente.

# data[].attributes.body
Aplicaciones de escritorio

En aplicaciones con interfaces gráficas, el patrón comando es comúnmente utilizado para delegar la responsabilidad de las interacciones del usuario a diferentes componentes, facilitando la organización del código y la implementación de nuevas funcionalidades.

# data[].attributes.body
Aplicaciones web

En frameworks como Spring para Java, el patrón de estrategia se utiliza para delegar la lógica de negocio a diferentes servicios, manteniendo la separación de preocupaciones y mejorando la modularidad.

# data[].attributes.body
Aunque el cambio de responsabilidad tiene muchas ventajas, también puede aumentar la complejidad del sistema si no se maneja adecuadamente. En sistemas muy grandes, el exceso de delegación puede generar dependencias circulares o dificultar la depuración del código.

# data[].attributes.body
Este patrón permite centralizar la comunicación entre diferentes objetos, reduciendo la complejidad y evitando dependencias directas entre ellos. El cambio de responsabilidad aquí es evidente, ya que se transfiere la lógica de comunicación a una clase mediadora.

# data[].attributes.headline
9. Implementación en frameworks y tecnologías modernas

# data[].attributes.subject
9. Implementación en frameworks y tecnologías modernas

# data[].attributes.body
Frameworks como Spring en Java y Django en Python implementan el cambio de responsabilidad mediante la inyección de dependencias, lo que permite una gestión eficiente de los servicios y la lógica de negocio. Esto facilita la reutilización de componentes y la modificación de funcionalidades sin afectar el sistema general

# data[].attributes.body
[1] Martin, R. C. (2000). Design principles and design patterns. Object Mentor. https://www.objectmentor.com/resources/articles/Principles_and_Patterns.pdf

[2]

# data[].attributes.body
El patrón de diseño Iterator permite recorrer secuencialmente los elementos de una colección sin exponer su representación interna. Facilita la implementación de colecciones iterables y la separación entre las estructuras de datos y los algoritmos que operan sobre ellas [1].

# data[].attributes.body
Las colecciones son uno de los tipos de datos más utilizados en programación. No obstante, una colección es sólo un contenedor para un grupo de objetos.

La mayoría de las colecciones almacenan sus elementos en listas simples. Sin embargo, algunos de ellos se basan en pilas, árboles, gráficos y otras estructuras de datos complejas.

Pero no importa cómo esté estructurada una colección, debe proporcionar alguna forma de acceder a sus elementos para que otro código pueda utilizarlos. Debería haber una manera de revisar cada elemento de la colección sin acceder a los mismos elementos una y otra vez.

Esto puede parecer un trabajo fácil si tiene una colección basada en una lista. Simplemente recorre todo los elementos. Pero, ¿cómo se atraviesan secuencial-mente elementos de una estructura de datos compleja, como un árbol? Por ejemplo un día podría estar bien con el recorrido de un árbol en profundidad. Sin embargo, al día siguiente es posible que necesite un recorrido en amplitud. Y la próxima semana, es posible que necesites algo mas, como acceso aleatorio a los elementos del árbol.

# data[].attributes.body
La idea principal del patrón iterador es extraer el comportamiento transversal de una colección en un objeto separado llamado iterador.

Además de implementar el algoritmo en sí, un objeto iterador encapsula todos los detalles de recorrido, como la posición actual y cuántos elementos quedan hasta el final. Debido a esto, varios iteradores pueden recorrer la misma colección al mismo tiempo, independientemente unos de otros.

# data[].attributes.body
Imagina que tienes dos cajas de libros. Una de ellas está organizada de manera secuencial, con los libros ordenados por tema o autor, mientras que la otra está llena de libros colocados de forma completamente aleatoria. Si quieres encontrar un libro específico, o simplemente recorrer todos los libros de la caja, en la primera caja (organizada), sería sencillo pasar de un libro al siguiente en un orden lógico. En la caja desorganizada, necesitarías algún mecanismo para moverte entre los libros, porque no hay un orden establecido.

Aquí es donde entra el patrón Iterator: sin importar cómo estén organizados los libros (la estructura interna de la colección), el Iterator te permite recorrer cada libro de manera uniforme, asegurándose de que puedas acceder a cada uno sin preocuparte de cómo están almacenados.

# data[].attributes.body
Iterator (Interfaz Iterator): Iterator<T>

Concrete Iterator (Iteradores concretos): LibrosIterator y RandomLibrosIterator

Collection (Colección abstracta): CajaDeLibros (aunque en este caso es la misma que la colección concreta)

Concrete Collection (Colección concreta): CajaDeLibros

# data[].attributes.body
El patrón Memento es un patrón de diseño de comportamiento que permite capturar y almacenar el estado interno de un objeto sin violar su encapsulamiento, para que el objeto pueda volver a ese estado más tarde. Se utiliza para implementar funciones de deshacer o restaurar en aplicaciones [2].

# data[].attributes.body
Imagina que estás creando una aplicación de edición de texto. Además de la edición de texto simple, su editor puede formatear el texto, insertar imágenes en línea, etc.

En algún momento, decidiste permitir a los usuarios deshacer cualquier operación realizada en el texto. Esta característica se ha vuelto tan común a lo largo de los años que hoy en día la gente espera que todas las aplicaciones la tengan. Para la implementación, optó por adoptar el enfoque directo. Antes de realizar cualquier operación, la aplicación registra el estado de todos los objetos y lo guarda en algún lugar de almacenamiento. Más tarde, cuando un usuario decide revertir una acción, la aplicación recupera la última instantánea del historial y la utiliza para restaurar el estado de todos los objetos.

# data[].attributes.body
El patrón sugiere almacenar la copia del estado del objeto en un objeto especial llamado memento. El contenido del memento no es accesible para ningún otro objeto, excepto para el que lo produjo. Otros objetos deben comunicarse con los mementos usando una interfaz limitada, que puede permitir acceder a meta datos de la instantánea (como el tiempo de creación, el nombre de la operación realizada, etc.), pero no al estado original que contiene la instantánea.

# data[].attributes.body
El patrón Memento puede explicarse con la analogía del papel carbón. Imagina que estás escribiendo en una máquina de escribir y debajo de la hoja principal colocas una hoja con papel carbón. Cada vez que escribes, el papel carbón guarda una copia exacta de lo que has escrito, pero esa copia no puede ser modificada directamente. Si en algún momento quieres restaurar lo que habías escrito antes, puedes sacar esa copia del papel carbón y volver al estado anterior. En esta analogía, la máquina de escribir es el objeto que genera el estado (el texto escrito), el papel carbón es el Memento que guarda una copia del estado, y el cajón donde guardas esas copias de papel carbón es el Caretaker, que se encarga de almacenar y restaurar esos estados sin tener acceso directo al contenido que guardan. Esto permite deshacer cambios y restaurar estados anteriores sin romper el encapsulamiento del objeto.

# data[].attributes.body
Originador (Originator): MaquinaDeEscribir – el objeto que genera y guarda su propio estado.

Memento: Memento – almacena el estado del Originador en un momento específico.

Cuidador (Caretaker): Caretaker – guarda y administra los Mementos sin conocer su contenido.

Cliente (Client): El código de simulación que interactúa con el Originador y el Caretaker para guardar y restaurar estados.

# data[].attributes.body
El patrón State es un patrón de diseño de comportamiento que permite a un objeto cambiar su comportamiento cuando su estado interno cambia. Desde el punto de vista del cliente, parece que el objeto cambia de clase. Este patrón es útil cuando un objeto debe cambiar su comportamiento dinámicamente dependiendo de su estado, evitando una gran cantidad de condicionales [3].

# data[].attributes.body
El patrón State proporciona una solución al encapsular los comportamientos dependientes del estado en clases separadas, lo que permite que el objeto principal delegue las acciones a sus estados correspondientes. Esto elimina los condicionales extensos y facilita la adición de nuevos estados sin modificar el código existente. Un ejemplo clásico es un sistema de máquina de estados finitas, donde un objeto puede cambiar su comportamiento dinámicamente según su estado actual.

# data[].attributes.body
El patrón de estado sugiere crear nuevas clases para todos los estados posibles de un objeto y extraer todos los comportamientos específicos del estado en estas clases.

En lugar de implementar todos los comportamientos por sí mismo, el objeto original, llamado contexto, almacena una referencia a uno de los objetos de estado que representa su estado actual, y delega todo el trabajo relacionado con el estado a este objeto.

# data[].attributes.body
Imagina un reproductor de música que tiene varios estados: bloqueado, reproduciendo y pausado. Cada estado tiene un comportamiento diferente cuando presionas los botones.

En el estado bloqueado, si presionas el botón de play, el reproductor no hará nada porque está bloqueado.

En el estado reproduciendo, si presionas el botón de play, el reproductor pausará la música.

En el estado pausado, si presionas el botón de play, el reproductor comenzará a reproducir la música nuevamente.

# data[].attributes.body
Document (Context): Corresponde a la clase MusicPlayer en el código, que es el objeto que delega el comportamiento a los estados y cambia su estado cuando es necesario.

State (Interfaz): Representa la interfaz State, que define los métodos que todos los estados deben implementar (play(), pause(), stop()).

Draft (Estado Concreto): En el código, esto corresponde a los estados concretos (PlayingState, PausedState, StoppedState), que implementan el comportamiento específico para cada estado del reproductor.

# data[].attributes.body
El patrón Strategy es una forma de organizar el código para que podamos elegir entre diferentes maneras de hacer algo, sin tener que cambiar toda la estructura del programa. Es como tener una caja de herramientas con diferentes llaves: todas hacen algo similar (apretar tornillos), pero se usan en situaciones diferentes [1].

# data[].attributes.body
Imagina que tienes tres maneras de ir al parque:

Caminando.

En bicicleta.

En autobús.

Aunque las tres opciones te llevan al mismo lugar, cada una lo hace de forma diferente. Esto es como el patrón Strategy: diferentes estrategias para hacer lo mismo (llegar al parque), pero cada una se guarda en su propio lugar (clase) y se puede cambiar fácilmente.

# data[].attributes.body
Contexto: Es la parte que decide qué estrategia utilizar (¿Caminar, bicicleta o autobús?).

Estrategias: Cada una de las maneras de hacer algo. Por ejemplo, caminar sería una estrategia, y montar en bicicleta sería otra.

Cliente: Es quien decide cuál estrategia usar. Por ejemplo, dependiendo del tiempo que tengas o de si hay autobuses, eliges una estrategia para ir al parque.

# data[].attributes.body
Cambio fácil de comportamiento

Código más limpio y organizado

Fácil de agregar nuevas estrategias

# data[].attributes.body
El Template Method es un patrón de diseño de comportamiento que permite definir los pasos de un algoritmo en una clase base, dejando que las clases derivadas modifiquen ciertos pasos sin cambiar la estructura general [1].

# data[].attributes.body
Imagina que estás haciendo un sándwich. Sabes que siempre necesitas hacer ciertos pasos como poner el pan, los ingredientes, y cerrar el sándwich. Pero, tal vez quieres cambiar los ingredientes, o el tipo de pan. El Template Method te permite seguir el "esqueleto" de cómo hacer un sándwich, pero puedes elegir tus propios ingredientes.

# data[].attributes.headline
¿Cómo funciona el Patrón Template method?

# data[].attributes.subject
¿Cómo funciona el Patrón Template method?

# data[].attributes.body
Clase Base: Define el proceso general con un método que sigue varios pasos.

Métodos Fijos y Personalizables: Algunos pasos ya están definidos, mientras que otros se dejan como vacíos o abstractos para que las subclases los definan.

Subclases: Las subclases modifican solo los pasos necesarios sin cambiar el proceso completo.

Estructura Inmutable: El proceso general no cambia, solo los detalles.

# data[].attributes.body
Reutilización

Flexibilidad

# data[].attributes.body
[1] FOP Olga Skobeleva, «Strategy», Refactoring. Disponible en: https://refactoring.guru/es/design-patterns/strategy

# data[].attributes.body
[1] FOP Olga Skobeleva, «Themplate Method», Refactoring. Disponible en: https://refactoring.guru/es/design-patterns/template-method

# data[].attributes.body
El patrón Visitor es un patrón de diseño de comportamiento que permite separar algoritmos (o comportamientos) de los objetos sobre los que operan. Esto significa que puedes añadir nuevas operaciones a una estructura de objetos sin modificar las clases de esos objetos [1].

# data[].attributes.body
Imagina un agente de seguros que visita diferentes tipos de edificios y ofrece seguros específicos según el tipo de edificio. El agente (Visitor) sabe qué ofrecer basándose en el tipo de edificio (Element).

# data[].attributes.body
Visitor (Visitante): Define qué hacer con cada tipo de objeto.

Element (Elemento): Los objetos aceptan al visitante y permiten que haga su trabajo.

ConcreteVisitor (Visitante Concreto): Implementa las operaciones específicas para cada tipo de objeto.

# data[].attributes.body
[1] FOP Olga Skobeleva, «Visitor», Refactoring. Disponible en: https://refactoring.guru/es/design-patterns/visitor

# data[].attributes.body
El patrón Mediator es un patrón de diseño de comportamiento que facilita la comunicación entre varios objetos sin que estos interactúen directamente entre sí, reduciendo las dependencias entre ellos. En lugar de que los objetos se comuniquen directamente, lo hacen a través de un mediador central, que se encarga de coordinar las interacciones. Esto ayuda a que el sistema sea más flexible y manejable, permitiendo cambiar las interacciones entre objetos sin modificarlos directamente [4].

# data[].attributes.body
Supongamos que tiene un cuadro de diálogo para crear y editar perfiles de clientes. Consta de varios controles de formulario, como campos de texto, casilla de verificación, botones, etc.

Algunos de los elementos del formulario pueden interactuar con otros. Por ejemplo, seleccionar la casilla "Tengo un perro" puede revelar un campo de texto oculto para ingresar el nombre del perro. Otro ejemplo es el botón de enviar que debe validar los valores de todos los campos antes de guardar los datos.

Los elementos pueden tener muchas relaciones con otros elementos. Por tanto, los cambios en algunos elementos pueden afectar a otros.

# data[].attributes.body
El patrón mediador sugiere que debe cesar toda comunicación directa entre los componentes que desea independizar entre sí. En cambio, estos componentes deben colaborar indirectamente, llamando a un objeto mediador especial que redirige las llamadas a los componentes apropiados. Como resultado, los componentes dependen sólo de una única clase mediadora en lugar de estar acoplados a decenas de sus de sus colegas.

# data[].attributes.body
Mediator Interface (Interfaz del Mediador): Mediador (define la interfaz notificar()).

Concrete Mediator (Mediador Concreto): DirectorDeOrquesta (coordina las interacciones entre los músicos).

Components (Componentes): Violinista, Pianista, Trompetista (los músicos que interactúan entre sí a través del mediador).

Client (Cliente): El código que instancia los componentes y el mediador, y comienza la secuencia de eventos.

# data[].attributes.body
[3] G. Gamma, R. Helm, R. Johnson, and J. Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley, 1994, pp. 305-313.

# data[].attributes.attachment_link.readable_text
Design patterns are typical solutions to common problems in software design. Each pattern is like a blueprint that you can customize to solve a particular design problem in your code.

Catalog of patterns

List of 22 classic design patterns, grouped by their intent.

Benefits of patterns

Patterns are a toolkit of solutions to common problems in software design. They define a common language that helps your team communicate more efficiently.

Classification

Design patterns differ by their complexity, level of detail and scale of applicability. In addition, they can be categorized by their intent and divided into three groups.

History of patterns

Who invented patterns and when? Can you use patterns outside software development? How do you do that?

Criticism of patterns

Are patterns as good as advertised? Is it always possible to use them? Can patterns sometimes be harmful?

Dive Into Design Patterns

Check out our ebook on design patterns and principles. It's available in PDF/ePUB/MOBI formats and includes the archive with code examples in Java, C#, C++, PHP, Python, Ruby, Go, Swift, & TypeScript.

# data[].attributes.attachment_link.description
Design Patterns are typical solutions to commonly occurring problems in software design. They are blueprints that you can customize to solve a particular design problem in your code.

# data[].attributes.body
Observer es un patrón de diseño de comportamiento que define una relación uno a muchos entre objetos, de manera que cuando un objeto cambia de estado, todos sus dependientes son notificados y actualizados automáticamente. Es comúnmente utilizado en sistemas donde diferentes componentes necesitan ser sincronizados sin estar fuertemente acoplados, como en sistemas de eventos o interfaces gráficas de usuario (GUI). [1]

# data[].attributes.body
[4] G. Gamma, R. Helm, R. Johnson, and J. Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley, 1994, pp. 273-282.

# data[].attributes.attachment_link.readable_text
Design patterns are typical solutions to common problems in software design. Each pattern is like a blueprint that you can customize to solve a particular design problem in your code.

Catalog of patterns

List of 22 classic design patterns, grouped by their intent.

Benefits of patterns

Patterns are a toolkit of solutions to common problems in software design. They define a common language that helps your team communicate more efficiently.

Classification

Design patterns differ by their complexity, level of detail and scale of applicability. In addition, they can be categorized by their intent and divided into three groups.

History of patterns

Who invented patterns and when? Can you use patterns outside software development? How do you do that?

Criticism of patterns

Are patterns as good as advertised? Is it always possible to use them? Can patterns sometimes be harmful?

Dive Into Design Patterns

Check out our ebook on design patterns and principles. It's available in PDF/ePUB/MOBI formats and includes the archive with code examples in Java, C#, C++, PHP, Python, Ruby, Go, Swift, & TypeScript.

# data[].attributes.attachment_link.description
Design Patterns are typical solutions to commonly occurring problems in software design. They are blueprints that you can customize to solve a particular design problem in your code.

# data[].attributes.body
[2] G. Gamma, R. Helm, R. Johnson, and J. Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley, 1994, pp. 283-292.

# data[].attributes.attachment_link.readable_text
Design patterns are typical solutions to common problems in software design. Each pattern is like a blueprint that you can customize to solve a particular design problem in your code.

Catalog of patterns

List of 22 classic design patterns, grouped by their intent.

Benefits of patterns

Patterns are a toolkit of solutions to common problems in software design. They define a common language that helps your team communicate more efficiently.

Classification

Design patterns differ by their complexity, level of detail and scale of applicability. In addition, they can be categorized by their intent and divided into three groups.

History of patterns

Who invented patterns and when? Can you use patterns outside software development? How do you do that?

Criticism of patterns

Are patterns as good as advertised? Is it always possible to use them? Can patterns sometimes be harmful?

Dive Into Design Patterns

Check out our ebook on design patterns and principles. It's available in PDF/ePUB/MOBI formats and includes the archive with code examples in Java, C#, C++, PHP, Python, Ruby, Go, Swift, & TypeScript.

# data[].attributes.attachment_link.description
Design Patterns are typical solutions to commonly occurring problems in software design. They are blueprints that you can customize to solve a particular design problem in your code.

# data[].attributes.body
[1] G. Gamma, R. Helm, R. Johnson, and J. Vlissides, Design Patterns: Elements of Reusable Object-Oriented Software, Addison-Wesley, 1994, pp. 257-271.

[5] https://refactoring.guru/design-patterns

# data[].attributes.attachment_link.readable_text
Design patterns are typical solutions to common problems in software design. Each pattern is like a blueprint that you can customize to solve a particular design problem in your code.

Catalog of patterns

List of 22 classic design patterns, grouped by their intent.

Benefits of patterns

Patterns are a toolkit of solutions to common problems in software design. They define a common language that helps your team communicate more efficiently.

Classification

Design patterns differ by their complexity, level of detail and scale of applicability. In addition, they can be categorized by their intent and divided into three groups.

History of patterns

Who invented patterns and when? Can you use patterns outside software development? How do you do that?

Criticism of patterns

Are patterns as good as advertised? Is it always possible to use them? Can patterns sometimes be harmful?

Dive Into Design Patterns

Check out our ebook on design patterns and principles. It's available in PDF/ePUB/MOBI formats and includes the archive with code examples in Java, C#, C++, PHP, Python, Ruby, Go, Swift, & TypeScript.

# data[].attributes.attachment_link.description
Design Patterns are typical solutions to commonly occurring problems in software design. They are blueprints that you can customize to solve a particular design problem in your code.

# data[].attributes.body
Observable: Es el objeto que está siendo observado. Puede haber cambios de estado en este objeto que son importantes para otros objetos.

ObserverA y ObserverB: Son los objetos observadores que se suscriben al objeto observable para ser notificados cuando ocurra un cambio de estado en él.

# data[].attributes.body
El patrón Observer respalda los principios SOLID:

# data[].attributes.body
Principio de Responsabilidad Única (SRP): Permite que los sujetos (objetos observados) se encarguen únicamente de actualizar su estado, delegando la responsabilidad de reacción en los observadores.

# data[].attributes.body
Principio de Inversión de Dependencias (DIP): Los observadores dependen de interfaces, no de implementaciones concretas, lo que permite que diferentes tipos de observadores respondan a cambios de estado. [2]

# data[].attributes.body
Un ejemplo típico es un sistema de notificaciones en el cual varios usuarios (observadores) reciben actualizaciones de un sistema central (sujeto). Cuando el sujeto cambia de estado (como un nuevo mensaje), todos los observadores registrados son notificados automáticamente.

# data[].attributes.body
Desacoplamiento: El sujeto y los observadores están desacoplados, lo que facilita la escalabilidad y el mantenimiento del sistema.

Extensibilidad: Se pueden agregar nuevos observadores sin modificar el código existente.

Flexibilidad en la notificación: Los observadores pueden registrarse y desregistrarse dinámicamente.

# data[].attributes.body
Un ejemplo típico es un sistema de notificaciones en el cual varios usuarios (observadores) reciben actualizaciones de un sistema central (sujeto). Cuando el sujeto cambia de estado (como un nuevo mensaje), todos los observadores registrados son notificados automáticamente.

# data[].attributes.body
Puede introducir complejidad en aplicaciones grandes con muchos observadores, especialmente cuando se requiere un control sobre el orden de las notificaciones o cuando el ciclo de vida de los observadores no está claramente definido

# data[].attributes.body
Patrón Mediador: Ambos patrones separan las interacciones entre objetos. Sin embargo, el mediador centraliza las interacciones, mientras que el Observer notifica a los observadores de manera distribuida.

Patrón Event-Driven: Este patrón tiene una relación similar con Observer, ya que muchos sistemas de eventos utilizan la mecánica de observación para notificar a los oyentes cuando ocurre un evento.

# data[].attributes.body
El patrón Command encapsula una solicitud como un objeto, permitiendo parametrizar clientes con diferentes solicitudes, poner en cola o registrar solicitudes, y soportar operaciones que se puedan deshacer. En lugar de que el cliente invoque directamente una operación, la solicitud se envuelve en un comando que puede ser ejecutado, deshecho o repetido según sea necesario.