Los ingenieros de Baidu te enseñan a jugar con el modo de diseño (modo observador)

imagen

Para escribir un buen código, Design Pattern es una habilidad básica esencial. Design Pattern es una solución efectiva a los problemas recurrentes en el Diseño Orientado a Objetos. Esta vez desde el patrón de observadores más común (Observer Pattern). En el modo de observador, hay múltiples dependencias de objetos de observador (Observador) que dependen del mismo objeto de destino (Sujeto). Cuando el objeto de destino dependiente cambia, todos los objetos de observador que dependen de él serán notificados, y luego cada observación El destinatario objeto responde en consecuencia de acuerdo a sus propias necesidades.

Sus principales ventajas son las siguientes:

  • Acoplamiento reducido entre el objetivo y el observador

  • Estableció un mecanismo de activación de cambio entre el objetivo y el observador.

Sus principales desventajas son las siguientes:

  • La dependencia entre el objetivo y el observador no está completamente resuelta, y existe la posibilidad de referencias circulares.

  • Cuando hay muchos objetos de observador, la publicación de la notificación lleva mucho tiempo, lo que afecta la eficiencia del programa.

¿Más abstracto y difícil de entender? Vamos a referirnos a varios escenarios comunes en el diseño funcional diario.

01 Aplicación del modo observador en la escena del pronóstico del tiempo

Prestar atención al pronóstico del tiempo es un hábito importante en nuestra vida diaria, diferentes roles tienen diferentes reacciones a los cambios en el clima. Por ejemplo, si mañana llueve mucho, el departamento meteorológico considera evaluar y emitir una guía de política razonable, el departamento de educación debe evaluar si es necesario suspender las clases, el departamento de emergencia considera cómo prepararse para el rescate de emergencia con anticipación y el El departamento de saneamiento debe prepararse para una gran cantidad de trabajos de saneamiento después de la tormenta. Debe pensar en cómo viajar hacia y desde el trabajo, y hay algunas personas en áreas no afectadas por esta fuerte lluvia que no necesitan pensar en cualquier cosa. Combinado con la introducción del modo de observador anterior, en este escenario, el clima pertenece al objeto de destino (Sujeto) del que depende cada rol, el departamento meteorológico/educativo/de emergencia/saneamiento y otros, trabajadores migrantes y personas en otras áreas pertenecen al objeto observador (Observador). ). Después de que cambie el objeto objetivo, cada objeto observador tomará las medidas de respuesta correspondientes después de recibir el mensaje. La versión simplificada del diagrama de clase del patrón de observador basado en el escenario anterior es el siguiente:

imagen

  • Objeto de destino (WeatherSubject): el objeto de destino que se observará, es decir, el clima en este ejemplo, tiene un estado de atributo de un estado del clima y vincula el método del observador added() y el método del observador notificar a Todos los Observadores(). Cuando cambie el estado, llame al método de notificación a todos los observadores () para notificar a todos los observadores.

  • Objeto Abstract Observer (Observer): se utiliza para definir la especificación de comportamiento de cada observador, y también se puede implementar en forma de interfaz

  • Objetos de observador reales: MeteorologicalDepartment, RescueDepartment, OfficeWorker, Other, etc., los roles que realmente necesitan prestar atención al objeto de destino y responder. Heredado del objeto observador abstracto e implementado el método de respuesta update() en función de sus respectivas preocupaciones.

Pruebe la demostración del código de la versión de Java basada en el ejemplo anterior:

package com;
import java.util.ArrayList;
import java.util.List;
// 基于天气预报场景的观察者模式实现Demo
public class ObserverPatternDemo {
    // 天气对象
    static class WeatherSubject {
        private int state;
        List<Observer> observers = new ArrayList<>();
        void attach(Observer observer) {
            observers.add(observer);
        }
        // 通知观察者
        void notifyAllObservers() {
            for (Observer o : observers
            ) {
                o.update(getState());
            }
        }
        public int getState() {
            return state;
        }
        // 状态变更
        public void setState(int state) {
            this.state = state;
            if (state == 1) {
                System.out.println("=====明天要下大暴雨=====");
            } else {
                System.out.println("=====明天天气很好呀=====");
            }
            // 变更后通知观察者
            notifyAllObservers();
        }
    }
    // 抽象观察者对象
    static abstract class Observer {
        abstract void update(int state);
    }
    // 政府气象部门
    static class MeteorologicalDepartment extends Observer {
        @Override
        void update(int state) {
            if (state == 1) {
                System.out.println("【气象部门】发出预警");
            }
        }
    }
    // 政府应急救援部门
    static class ResumeDepartment extends Observer {
        @Override
        void update(int state) {
            if (state == 1) {
                System.out.println("【救援部门】准备应急预案");
            }
        }
    }
    // 打工人
    static class OfficeWorker extends Observer {
        @Override
        void update(int state) {
            if (state == 1) {
                System.out.println("【打工人】思考明天怎么上下班通勤");
            } else {
                System.out.println("【打工人】努力搬砖");
            }
        }
    }
    // 其他无影响的人
    static class Other extends Observer {
        @Override
        void update(int state) {
            if (state == 1) {
                System.out.println("【其他人】下雨啊,对我影响不大");
            } else {
                System.out.println("【其他人】明天天气不错,出去玩玩");
            }
        }
    }
    public static void main(String[] args) {
        // 初始化目标对象
        WeatherSubject subject = new WeatherSubject();
        // 初始化观察者对象,并关注目标对象
        Observer ob1 = new MeteorologicalDepartment();
        Observer ob2 = new ResumeDepartment();
        Observer ob3 = new OfficeWorker();
        Observer ob4 = new Other();
        subject.attach(ob1);
        subject.attach(ob2);
        subject.attach(ob3);
        subject.attach(ob4);
        // 状态变化: 大暴雨
        subject.setState(1);
        // 状态变化: 好天气
        subject.setState(2);
        
        //执行结果如下
        =====明天要下大暴雨=====
        【气象部门】发出预警
        【救援部门】准备应急预案
        【打工人】思考明天怎么上下班通勤
        【其他人】下雨啊,对我影响不大
        =====明天天气很好呀=====
        【打工人】努力搬砖
        【其他人】明天天气不错,出去玩玩
    }
}

02 Aplicación del Modo Observador en Escenarios de Pago

En el escenario comercial de pago, cuando un usuario compra un producto, las tres partes se llamarán a sí mismas después de que el pago sea exitoso. En este momento, el sistema puede tener mucha lógica que debe ejecutarse (como: actualizar el pedido estado, enviar notificaciones por SMS, avisar al sistema logístico para iniciar el aprovisionamiento, dar regalos…).

Por lo general, el método de procesamiento más intuitivo es crear las clases de las que debe depender el sistema de pago correspondiente (Pedido, SMS, Express...) y la clase de pago Pagar, e instanciar cada clase de dependencia en la lógica de pago principal. paga con éxito, llámelos uno por uno Lógica de procesamiento de clase de dependencia. Sin embargo, de esta manera, la clase de pago necesita saber qué clases necesitan ser notificadas, y la lógica de pago principal está inflada y acoplada, lo que es un inconveniente para la expansión y el mantenimiento.

El modo de observador puede manejar mejor tales escenarios de pago. No existe un fuerte acoplamiento entre las lógicas de clase en las que se basan estos sistemas de pago, por lo que es adecuado usar el modo de observador para implementar estas funciones, y la clase de pago no se preocupa por la necesidad. para notificación Para qué clases, solo necesita proporcionar una lista de notificación Cuando hay más operaciones, solo necesita agregar un nuevo observador a la lista de notificación, y el usuario paga con éxito para notificar a todos los observadores registrados. Se implementa el principio abierto-cerrado de cerrado a modificación y abierto a extensión.

La implementación específica generalmente incluye las siguientes partes:

  • Resumen de la clase Observable observada, propiedades y métodos comunes abstractos;

  • Cree una clase de pago de observador específica, siempre que el usuario pague con éxito, notificará a todos los observadores registrados;

  • Resumen de la interfaz del observador Observer, que contiene un método abstracto de actualización que se actualiza a sí mismo, al que se llama cuando se recibe una notificación de cambio del tema específico Pagar;

  • Cree clases de observadores específicas, como pedidos, SMS, logística, etc., necesitan observar el estado de pago y actualizar su propio estado cuando reciben la notificación de cambio de Pago;

// 抽象主题(Subject)角色
public abstract class Observable {
 // 观察者列表
 private List<Observer> observers = new ArrayList<>();
 // 添加观察者
 public void add(Observer observer){
  observers.add(observer);
 }
 // 移除观察者
 public void remove(Observer observer){
  observers.remove(observer);
 }
 // 通知观察者
 protected void notifyObservers(){
  for (Observer observer : observers) {
   observer.update();
  }
 }
}
// 具体主题(Concrete Subject)角色
public class Pay extends Observable{
 public void pay(){
  System.out.println("支付完成.");
  // 通知观察者
  super.notifyObservers();
 }
}
// 抽象观察者(Observer)角色
public interface Observer {
 // 通知
 void update();
}
// 具体观察者(Concrete Observer)角色
// 订单:修改订单状态
public class Order implements Observer{
 @Override
 public void update() {
  System.out.println("修改订单状态...");
 }
}
// 短信:发送扣款短信到用户
public class SMS implements Observer{
 @Override
 public void update() {
  System.out.println("账户扣款短信通知...");
 }
}
//物流:通知物流系统开始备货
public class Express implements Observer{
 @Override
 public void update() {
  System.out.println("物流开始备货...");
 }
}
// 客户端调用
public class Client {
 public static void main(String[] args) {
  Pay pay = new Pay();
  pay.add(new Order());
  pay.add(new SMS());
  pay.add(new Express());
  pay.pay();
 }
}

03 Aplicación del Patrón de Observador en el Escenario de Suscripción de Datos

En aplicaciones prácticas, el modo de observador se usa a menudo en el escenario de envío de datos. Tomando recursos novedosos como ejemplo, después de que se completa la producción de un nuevo capítulo, hay muchas empresas que necesitan los datos, como búsqueda, disco en línea, barra de correos, Xiaodu, etc., y cada parte recibe los datos de diferentes maneras. .

Para cada suscriptor, se implementará un método de suscripción completamente diferente, que puede ser una interfaz push http, una cola kafka, un sistema de archivos afs, etc. Estos métodos de suscripción pueden implementarse por separado y registrarse.Cuando se publica un mensaje, los métodos de suscripción se activan a su vez.

La siguiente es la demostración de implementación del lenguaje PHP:

interface Observer {
    public function push($data);
}
class Publish {
    private $observers = array();
    
    public function register(Observer $observer) {
        $this->observers[] = $observer;
    }
    
    public function delete(Observer $observer) {
        $index = array_search($observer, $this->observers);
        if ($index !== FALSE && array_key_exists($index, $this->observers)) {
            unset($this->_observers[$index]);
        }
    }
    
    public function push($data) {
        foreach ($this->observers as $observer) {
            $observer->push($data);
        }
    }
}
class Search implements Observer {
    public function push($data) {
        //推送afs
    }
}
class Cloud implements Observer {
    public function push($data) {
        //推送kafaka
    }
}
$publish = new Publish();
$publish->register(new Search());
$publish->register(new Cloud());
$publish->push($data);

04 Resumen

A través de la explicación de los tres casos prácticos anteriores y la lectura de la implementación del código específico, debe tener una comprensión más profunda de los escenarios de aplicación y los esquemas de implementación específicos del modo observador. Combinando el análisis de los tres casos anteriores, las escenas adecuadas para el modo observador tienen las siguientes características típicas:

  • Hay una dependencia de muchos a uno: es decir, múltiples observadores dependen del mismo objeto de destino

  • Hay un mecanismo de activación de cambio de objetivo: después de que cambia el objetivo, es necesario activar una serie de otras tareas

Para lograr los escenarios anteriores a través del mecanismo del observador, se puede lograr el desacoplamiento de la clase de destino y la clase de observador, es decir, el objeto de destino no necesita saber qué observadores deben ser notificados, lo cual es conveniente para la posterior expansión y mantenimiento. .

---------- FINAL ----------

Serie de lecturas recomendadas [Gasolinera técnica]:

Los ingenieros de Baidu te enseñan a jugar con patrones de diseño (patrón singleton)

Los ingenieros de Baidu le enseñan consejos para mejorar rápidamente la eficiencia de I+D

imagen

{{o.nombre}}
{{m.nombre}}

Supongo que te gusta

Origin my.oschina.net/u/4939618/blog/5551290
Recomendado
Clasificación