[Patrones y paradigmas de diseño: comportamiento] 71 | Modo de comando: ¿Cómo usar el modo de comando para implementar una arquitectura de back-end de juego móvil?

El módulo de patrones de diseño está llegando a su fin, y ahora solo nos quedan 3 patrones por aprender, ellos son: patrón de comando, patrón de intérprete y patrón de intermediario. Estos tres modos se usan con poca frecuencia y son difíciles de entender, y solo se usan en escenarios de aplicaciones muy específicos. Por lo tanto, no son el foco de nuestro estudio. Solo necesita entender un poco y puede reconocerlos cuando los vea. .

Hoy, aprendamos el modo de comando. En el proceso de aprendizaje de este modo, la mayor duda que puede encontrar es que siente que el modo de comando es inútil, es un diseño excesivo y hay ideas de diseño más simples que pueden reemplazarse. Por lo tanto, el enfoque de mi explicación de hoy es la intención del diseño de este modo, y lo llevará a descubrir bajo qué circunstancias realmente necesita usarlo.

Sin más preámbulos, ¡comencemos oficialmente el estudio de hoy!

Interpretación del principio del modo de comando.

La traducción al inglés del modo de comando es Patrón de diseño de comando. En el libro "Patrones de diseño" de GoF, se define así:

El patrón de comando encapsula una solicitud como un objeto, lo que nos permite parametrizar otros objetos con diferentes solicitudes, solicitudes de cola o registro, y admitir operaciones que se pueden deshacer.

La traducción al chino es la siguiente. Para ayudarlo a comprender, he complementado y explicado ligeramente esta traducción, y la he puesto entre paréntesis a continuación.

El modo de comando encapsula la solicitud (comando) como un objeto, de modo que se pueden usar diferentes solicitudes para parametrizar otros objetos (se inyectan diferentes dependencias de solicitud en otros objetos), y puede admitir la ejecución en cola, el registro y la revocación de solicitudes (comandos). ), etc. (control adicional) función.

Para la definición dada por GoF, la interpretaré mejor aquí.

Cuando se trata de la implementación de códigos, el método de implementación central que se usa en el modo de comando es encapsular funciones en objetos. Sabemos que el lenguaje C admite punteros de función y podemos pasar funciones como variables. Sin embargo, en la mayoría de los lenguajes de programación, las funciones no se pueden pasar como parámetros a otras funciones, ni se pueden asignar a variables. Con el patrón de comando, podemos encapsular funciones en objetos. Específicamente, diseñe una clase que contenga esta función, cree una instancia de un objeto y páselo, para que la función pueda usarse como un objeto. Desde el punto de vista de la implementación, es similar a la devolución de llamada de la que hablamos antes.

Cuando encapsulamos la función en un objeto, el objeto se puede almacenar para facilitar el control y la ejecución. Por lo tanto, la función principal y los escenarios de aplicación del modo de comando son para controlar la ejecución de comandos, como asincrónicos, retrasados, en cola de comandos, deshacer y rehacer comandos, almacenar comandos, registrar registros para comandos, etc. Esto es lo que el modo de comando puede hacer Un lugar para desempeñar un papel único.

Explicación práctica del modo comando

La explicación anterior es más teórica y difícil de entender, la explicaré con un ejemplo específico aquí.

Supongamos que estamos desarrollando un juego móvil como "Daily Cool Running" o "QQ Kart". La complejidad del juego en sí se concentra en el lado del cliente. Básicamente, el backend solo se encarga de actualizar y consultar datos (como puntos, salud y equipos), por lo que la lógica del backend es mucho más simple que la del cliente.

Teniendo en cuenta que es posible que no esté familiarizado con el desarrollo de juegos, explicaré algunos conocimientos básicos aquí.

Para mejorar el rendimiento, guardaremos la información de los jugadores en el juego en la memoria. Durante el juego, solo se actualizan los datos en la memoria y, una vez finalizado el juego, los datos en la memoria se archivan, es decir, se conservan en la base de datos. Para reducir la dificultad de implementación, en términos generales, los jugadores en la misma escena del juego serán asignados al mismo servidor. De esta manera, cuando un jugador extrae la información de otros jugadores en la misma escena del juego, no hay necesidad de buscar entre servidores y la implementación es mucho más simple.

En términos generales, la interacción de datos entre el cliente del juego y el servidor es relativamente frecuente, por lo tanto, para ahorrar la sobrecarga de establecer una conexión de red, el cliente y el servidor generalmente usan una conexión larga para comunicarse. Hay muchos formatos de comunicación, como Protocol Buffer, JSON, XML e incluso formatos personalizados. Independientemente del formato, la solicitud enviada por el cliente al servidor generalmente incluye dos partes: instrucciones y datos. Entre ellos, la instrucción también puede denominarse evento, y los datos son los datos necesarios para ejecutar la instrucción.

Después de recibir la solicitud del cliente, el servidor analizará las instrucciones y los datos y ejecutará diferentes lógicas de procesamiento de acuerdo con diferentes instrucciones. Para tal escenario empresarial, generalmente hay dos ideas de implementación de arquitectura.

Una idea de implementación comúnmente utilizada es usar subprocesos múltiples. Un subproceso recibe la solicitud y, después de recibirla, se inicia un nuevo subproceso para procesar la solicitud. Específicamente, la solicitud del cliente generalmente se recibe a través de un hilo principal. Cada vez que se recibe una solicitud, se toma un subproceso inactivo de un grupo de subprocesos dedicado a procesar la solicitud para su procesamiento.

Otra idea de implementación es sondear la solicitud de recepción y procesar la solicitud en un hilo. Este tratamiento es menos común. Aunque no puede aprovechar las ventajas del procesamiento multihilo y multinúcleo, para las empresas que hacen un uso intensivo de E/S, evita la pérdida de rendimiento causada por el cambio continuo de multihilo y supera las deficiencias de los errores de programación multihilo. que son difíciles de depurar Es un patrón arquitectónico común en el desarrollo de servidores back-end.
A continuación, nos centraremos en el segundo método de implementación.

Todo el servidor back-end del juego móvil sondea para obtener la solicitud del cliente. Después de obtener la solicitud, utiliza el modo de comando para encapsular los datos y la lógica de procesamiento contenida en la solicitud en un objeto de comando y almacenarlo en la cola de memoria. Luego, tome una cierta cantidad de comandos de la cola para ejecutar. Una vez completada la ejecución, comience una nueva ronda de sondeo nuevamente. El código de muestra específico es el siguiente, pueden verlo juntos.

public interface Command {
  void execute();
}
public class GotDiamondCommand implements Command {
  // 省略成员变量
  public GotDiamondCommand(/*数据*/) {
    //...
  }
  @Override
  public void execute() {
    // 执行相应的逻辑
  }
}
//GotStartCommand/HitObstacleCommand/ArchiveCommand类省略
public class GameApplication {
  private static final int MAX_HANDLED_REQ_COUNT_PER_LOOP = 100;
  private Queue<Command> queue = new LinkedList<>();
  public void mainloop() {
    while (true) {
      List<Request> requests = new ArrayList<>();
      
      //省略从epoll或者select中获取数据,并封装成Request的逻辑,
      //注意设置超时时间,如果很长时间没有接收到请求,就继续下面的逻辑处理。
      
      for (Request request : requests) {
        Event event = request.getEvent();
        Command command = null;
        if (event.equals(Event.GOT_DIAMOND)) {
          command = new GotDiamondCommand(/*数据*/);
        } else if (event.equals(Event.GOT_STAR)) {
          command = new GotStartCommand(/*数据*/);
        } else if (event.equals(Event.HIT_OBSTACLE)) {
          command = new HitObstacleCommand(/*数据*/);
        } else if (event.equals(Event.ARCHIVE)) {
          command = new ArchiveCommand(/*数据*/);
        } // ...一堆else if...
        queue.add(command);
      }
      int handledCount = 0;
      while (handledCount < MAX_HANDLED_REQ_COUNT_PER_LOOP) {
        if (queue.isEmpty()) {
          break;
        }
        Command command = queue.poll();
        command.execute();
      }
    }
  }
}

Patrón de comando VS Patrón de estrategia

Después de leer la explicación de hace un momento, puede sentir que el modo de comando es muy similar al modo de estrategia y al modo de fábrica, entonces, ¿cuál es la diferencia entre ellos? No solo eso, sino que en el área de mensajes, también vi a más de un estudiante reportando que muchos de los modelos que he aprendido son muy similares. Me pregunto si tienes un sentimiento similar.
De hecho, mencioné este tema brevemente antes, y puede que no sea el enfoque.Algunos estudiantes no están muy impresionados, así que te lo diré nuevamente aquí.

De hecho, cada patrón de diseño debe estar compuesto por dos partes: la primera parte es el escenario de aplicación, es decir, qué tipo de problemas puede resolver este patrón; la segunda parte es la solución, es decir, la idea de diseño y la implementación específica del código. de este patrón. Sin embargo, la implementación del código no tiene que estar incluida en el patrón. Si se enfoca únicamente en la parte de la solución, o incluso en la implementación del código, puede dar la ilusión de que la mayoría de los patrones se ven similares.

De hecho, la principal diferencia entre los patrones de diseño radica en la intención del diseño, que es el escenario de la aplicación. Simplemente mirando las ideas de diseño o la implementación del código, algunos patrones son muy similares, como el patrón de estrategia y el patrón de fábrica.

Cuando hablábamos antes del patrón de estrategia, mencionamos que el patrón de estrategia incluye tres partes: la definición, la creación y el uso de la estrategia.Desde la estructura del código, es muy similar al patrón de fábrica. La diferencia entre ellos es que el patrón de estrategia se centra en el escenario de aplicación específico de "estrategia" o "algoritmo", que se utiliza para resolver el problema de seleccionar diferentes estrategias de un conjunto de estrategias según el estado de tiempo de ejecución, mientras que el patrón de fábrica se enfoca en el proceso de creación de objetos encapsulados, aquí el objeto de no está limitado por ningún escenario de negocio, puede ser una estrategia, pero también pueden ser otras cosas. Desde la intención del diseño, estos dos modos son cosas completamente diferentes.

Con el presagio justo ahora, a continuación, veamos la diferencia entre el modo de comando y el modo de estrategia. Puede pensar que la lógica de ejecución de los comandos también puede considerarse una estrategia, entonces, ¿es un patrón de estrategia? En realidad, hay una ligera diferencia entre los dos.

En el patrón de estrategia, diferentes estrategias tienen el mismo propósito, diferentes implementaciones y pueden reemplazarse entre sí. Por ejemplo, BubbleSort y SelectionSort se utilizan para implementar la ordenación, pero una se implementa mediante el algoritmo de ordenación por burbuja y la otra se implementa mediante el algoritmo de ordenación por selección. En el modo de comando, diferentes comandos tienen diferentes propósitos, corresponden a diferentes lógicas de procesamiento y son insustituibles entre sí.

revisión clave

Bueno, eso es todo por el contenido de hoy. Resumamos y revisemos juntos, en qué necesitas concentrarte.

El modo de comando no se usa comúnmente en el trabajo diario, solo necesita comprenderlo un poco. Hoy me enfoqué en explicar la intención de su diseño, es decir, qué problemas puede resolver.

Cuando se trata de la implementación de códigos, el método de implementación central que se usa en el modo de comando es encapsular funciones en objetos. Sabemos que en la mayoría de los lenguajes de programación, las funciones no se pueden pasar como parámetros a otras funciones, ni se pueden asignar a variables. Con el patrón de comando, encapsulamos funciones en objetos, de modo que las funciones se puedan usar como objetos.

La función principal y los escenarios de aplicación del modo de comando son controlar la ejecución de comandos, como asincrónicos, retrasados, en cola de comandos, deshacer y rehacer comandos, almacenar comandos, registrar registros para comandos, etc. Esta es la singularidad del modo de comando .donde funciona.

discusión en clase

A partir de los patrones de diseño que hemos aprendido, encuentre dos patrones con implementación de código o ideas de diseño similares y hable sobre sus diferencias.

おすすめ

転載: blog.csdn.net/qq_32907491/article/details/131275466