El patr贸n de dise帽o del observador en Java

    Introducci贸n

    En este art铆culo, implementaremos el patr贸n de dise帽o del observador para resolver un problema com煤n en el desarrollo de software orientado a objetos.

    Los patrones de dise帽o son soluciones estandarizadas para problemas comunes en la industria del desarrollo de software. Al estar familiarizado con ellos, un desarrollador puede reconocer d贸nde deber铆a implementarse cada uno y c贸mo ayudar铆a a resolver un problema de dise帽o en particular.

    La prevenci贸n de desastres de dise帽o temprano puede ahorrar una gran cantidad de tiempo y costo para un equipo que intenta lanzar un producto.

    Patrones de dise帽o de comportamiento

    Los patrones de dise帽o de comportamiento proporcionan asignaci贸n de responsabilidad entre instancias de clases. Adem谩s, definen tipos de relaciones y comunicaci贸n entre objetos.

    La idea principal es lograr un comportamiento esperado de una aplicaci贸n y crear un dise帽o flexible al mismo tiempo.

    Patr贸n de dise帽o del observador

    El patr贸n de dise帽o del observador es una forma de dise帽ar un subsistema que permite que muchos objetos respondan autom谩ticamente a los cambios de un objeto en particular que est谩 siendo “observado”.

    Aborda la descomposici贸n de un Observable y Observers – o un editor y suscriptores.

    Por un Observable objeto, usamos el t茅rmino Sujeto. Los objetos que est谩n suscritos a los cambios del Sujeto se denominan Observadores. Un sujeto y los observadores suelen depender de uno a varios.

    El patr贸n de dise帽o del observador tambi茅n se conoce como patr贸n de evento-suscriptor o de escucha.

    Nota: Java tiene una implementaci贸n oficial del Observer Design Pattern y es la columna vertebral de JMS (Java Message Service). Generalmente se usa para crear aplicaciones impulsadas por pares, sin embargo, la implementaci贸n oficial no est谩 muy extendida y muchas personas implementan el patr贸n de acuerdo con sus propios casos de uso.

    Motivaci贸n

    Probablemente, el ejemplo m谩s conocido es un oyente de botones que realiza una acci贸n al hacer clic en el bot贸n. Este patr贸n, en general, es bastante com煤n en los componentes de la GUI de Java. Es una forma de reaccionar ante eventos que suceden con objetos visuales.

    Como usuario de las redes sociales, es posible que est茅 siguiendo a algunas personas. Podemos decir que eres un observador de las redes sociales de tu amigo (sujeto de observaci贸n) y recibes notificaciones sobre sus nuevas publicaciones y eventos de la vida. Curiosamente, tu amigo tambi茅n es un observador de tu feed.

    Agreguemos m谩s complejidad y digamos que probablemente tenga varios o incluso cientos de observadores diferentes y ellos pueden reaccionar de manera diferente a sus publicaciones. Es posible que un objeto pueda ser sujeto de observaci贸n y observador de otro sujeto. Incluso pueden tener esta relaci贸n entre ellos.

    Como ejemplo m谩s real: una alarma contra incendios en un centro comercial debe notificar a todas las tiendas que se est谩 produciendo un incendio. Estas tiendas est谩n observando la se帽al de alarma contra incendios y reaccionando a sus cambios.

    Como puede ver, el problema est谩 bastante extendido y muchas veces no es trivial resolverlo con otros dise帽os.

    Implementaci贸n

    Supongamos que una cadena de tiendas desea notificar a sus clientes leales sobre una venta en curso. El sistema enviar铆a un mensaje corto a todos los clientes suscritos cada vez que se activa una venta.

    En este caso, nuestra tienda es objeto de observaci贸n y nuestros clientes la est谩n observando. Definamos el Subject y Observer interfaces para que implementen nuestros objetos:

    public interface Subject {
        public void addSubscriber(Observer observer);
        public void removeSubscriber(Observer observer);
        public void notifySubscribers();
    }
    

    los Subject La interfaz es bastante sencilla. Proporciona m茅todos para agregar y eliminar suscriptores / observadores y notificarles un cambio.

    los Observer la interfaz es a煤n m谩s simple:

    public interface Observer {
        public void update(String message);
    }
    

    Lo 煤nico que un Observer lo que realmente necesita es saber cu谩ndo hay una actualizaci贸n de su tema. Su comportamiento basado en esta actualizaci贸n diferir谩 entre clases.

    Con nuestras interfaces fuera del camino, implementemos el Subject interfaz a trav茅s de una tienda:

    public class Store implements Subject {
        private List<Observer> customers = new ArrayList<>();
    
        @Override
        public void addSubscriber(Observer customer) {
            customers.add(customer);
        }
        @Override
        public void removeSubscriber(Observer customer) {
            customers.remove(customer);
        }
        @Override
        public void notifySubscribers() {
            System.out.println("A new item is on sale! Act fast before it sells out!");
            for(Observer customer: customers) {
                customer.update("Sale!");
            }
        }
    }
    

    La tienda contiene una lista de observadores (clientes) e implementa los m茅todos para la adici贸n y eliminaci贸n de clientes de la lista.

    los notifySubscribers() El m茅todo simplemente recorre la lista de ellos y les env铆a una actualizaci贸n.

    Podemos tener tantos Observer implementaciones como nos gustar铆a. Es natural que las personas reaccionen de manera diferente a una venta. Un adicto a las compras probablemente saltar谩 de alegr铆a, mientras que un cliente pasivo probablemente tomar谩 nota de la venta y la recordar谩 para m谩s adelante.

    Avancemos e implementemos estos dos tipos de clientes:

    public class ShopaholicCustomer implements Observer {
        @Override
        public void update(String message) {
            processMessage(message);
        }
        private void processMessage(String message) {
            System.out.println("Shopaholic customer is interested in buying the product on sale!");
            // A complex psychologic response to a sale by a shopaholic
        }
    }
    
    public class PassiveCustomer implements Observer {
        @Override
        public void update(String message) {
            System.out.println("Passive customer made note of the sale.");
            // Passive customer does not react to the message too much
        }
    }
    

    Y finalmente, echemos un vistazo al patr贸n de dise帽o del observador en acci贸n al activar una venta en una tienda que est谩 siendo vista por algunos clientes:

    public static void main(String[] args) {
        // Initialization
        Subject fashionChainStores = new ChainStores();
        Observer customer1 = new PassiveCustomer();
        Observer customer2 = new ShopaholicCustomer();
        Observer customer3 = new ShopaholicCustomer();
    
        // Adding two customers to the newsletter
        fashionChainStores.addSubscriber(customer1);
        fashionChainStores.addSubscriber(customer2);
    
        // Notifying customers (observers)
        fashionChainStores.notifySubscribers();
    
        // A customer has decided not to continue following the newsletter
        fashionChainStores.removeSubscriber(customer1);
    
        // customer2 told customer3 that a sale is going on
        fashionChainStores.addSubscriber(customer3);
    
        // Notifying the updated list of customers
        fashionChainStores.notifySubscribers();
    }
    

    Y ejecutar este fragmento de c贸digo producir谩:

    A new item is on sale! Act fast before it sells out!
    Passive customer made note of the sale.
    Shopaholic customer is interested in buying the product on sale!
    A new item is on sale! Act fast before it sells out!
    Shopaholic customer is interested in buying the product on sale!
    Shopaholic customer is interested in buying the product on sale!
    

    Cambiar el estado de la tienda da como resultado el cambio de estado de los clientes suscritos. Este mismo principio se aplicar铆a a una alarma de incendio o un servicio de noticias. Tan pronto como alguien publica una publicaci贸n, todos los observadores son notificados y toman alguna acci贸n dependiendo de su responsabilidad / inter茅s.

    Podemos modificar la lista de observadores de un sujeto en cualquier momento. Adem谩s, podemos agregar cualquier implementaci贸n del Observer interfaz. Esto nos da la capacidad de construir un sistema robusto impulsado por eventos que env铆a actualizaciones a los observadores y actualiza todo el sistema en funci贸n de los cambios en un solo objeto en particular.

    Pros y contras

    El patr贸n de dise帽o del observador es una gran contribuci贸n al apoyo del principio de dise帽o de apertura / cierre. Nos ayuda a construir dise帽os con alta cohesi贸n pero un acoplamiento flojo.

    En otras palabras, el Observador y el Sujeto tienen una misi贸n estrictamente especificada. El sujeto actualiza a un observador con cierta informaci贸n y no conoce la implementaci贸n del observador. Esta caracter铆stica nos da flexibilidad.

    Este patr贸n nos permite agregar y eliminar observadores en cualquier momento. No es necesario que modifique el sujeto ni el observador.

    Sin embargo, hay un problema en el patr贸n de dise帽o del observador.

    El orden de las notificaciones no est谩 bajo nuestro control. No hay prioridad entre los suscriptores durante la notificaci贸n.

    Esto significa que si la ejecuci贸n de un Observer depende de la ejecuci贸n de otro Observador de antemano, no hay garant铆a de que estos dos se ejecuten en ese orden.

    Sin embargo, es valioso comprender que un patr贸n es una descripci贸n de alto nivel de una soluci贸n en particular. Cuando aplicamos un patr贸n a dos aplicaciones diferentes, nuestro c贸digo ser谩 diferente. Podemos ordenar a nuestros observadores y recibir谩n una notificaci贸n en el orden esperado. Esta no es una caracter铆stica del patr贸n de dise帽o del observador, pero es algo que podemos hacer.

    Conclusi贸n

    Cuando conoce los patrones de dise帽o, algunos problemas complejos se pueden reducir a soluciones simples probadas.

    El patr贸n de dise帽o del observador es realmente 煤til en sistemas controlados por eventos donde muchos objetos pueden depender del estado de otro objeto. Si se implementa mal, esto dar谩 como resultado una aplicaci贸n r铆gida y acoplada donde es realmente dif铆cil probar los objetos individualmente y actualizar el c贸digo ser谩 una molestia.

    En este art铆culo, exploramos c贸mo podemos resolver este problema y crear una soluci贸n flexible y desacoplada que su equipo agradecer谩.

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *