¿Qué deberían usar los complementos: ganchos, eventos u otra cosa?

24

Considere una aplicación que permita que los complementos reaccionen a su flujo de programa.

Conozco 2 formas de lograr esto: ganchos y eventos

1. Ganchos

Use llamadas para vaciar funciones dentro del flujo del programa principal. Estas funciones pueden ser anuladas por complementos.

Por ejemplo, Drupal CMS implementa ganchos que están disponibles para módulos y temas. Aquí hay un ejemplo de cómo se implementa hook en una función file_copy .

function file_copy(stdClass $source, $destination = NULL, $replace = FILE_EXISTS_RENAME) {
    // ... [File copying routine]

    // Inform modules that the file has been copied.
    module_invoke_all('file_copy', $file, $source);

    return $file;
    // ...
}

Un módulo puede implementar una modulename_file_copy($file, $source)función que será llamada por module_invoke_allin file_copy. Una vez que finalice esta función, file_copyse reanudará la ejecución.

2. Eventos

Haga que la aplicación envíe eventos, que los complementos pueden escuchar. Después de recibir un evento al que se ha suscrito, un complemento interceptará el flujo del programa y realizará las operaciones necesarias.

Por ejemplo, un complemento de la galería jQuery Fotorama implementa varios eventos . Como ejemplo, aquí hay una parte de su showmétodo que dispara el fotorama:showevento.

  that.show = function (options) {
    // ... [show the new frame]

    // [fire the event]
    options.reset || triggerEvent('show', {
      user: options.user,
      time: time
    });

    // ... [do lots of other stuff with navigation bars, etc.]
  };

Un script puede escuchar este evento y hacer algo cuando se dispara:

$('.fotorama').on(
  'fotorama:show',
  function (e, fotorama, extra) {
    console.log(e.type + (extra.user ? ' after user’s touch' : ''));
    console.log('transition duration: ' + extra.time);
  }
);

PREGUNTA

  1. ¿Hay otras formas convencionales de implementar dicho comportamiento de complemento?

  2. Si no es así, ¿cuándo se deben usar ganchos y cuándo se deben usar eventos? Teniendo en cuenta que el objetivo final es hacer que el código sea más fácil de mantener y leer, tanto desde la aplicación como desde la perspectiva del desarrollador del complemento.

sbichenko
fuente

Respuestas:

17

La principal diferencia entre un gancho y un evento es el acoplamiento flojo versus el acoplamiento apretado.

Un gancho es una forma genérica de transmitir que algo ha sucedido. Puede agregar nuevos ganchos sin tener que volver a compilar complementos, y todos los ganchos siguen un patrón de diseño genérico. Una vez que se define la API de enlace, no cambia, por lo que no es probable que se rompa el acoplamiento entre la aplicación y el complemento.

Los eventos están más estrechamente relacionados con la aplicación. Los eventos pueden definir los parámetros que se adjuntan al evento, y si cambia esos parámetros, rompe la API con los complementos existentes.

Ambos logran los mismos resultados. Solo depende de cómo desee acoplar el complemento a la aplicación.

Hooks puede ofrecerle un acoplamiento más dinámico que no es probable que se rompa a medida que se lanzan nuevas versiones de su aplicación, pero la desventaja es que no recibe advertencias en tiempo de compilación de que los complementos ya no son compatibles.

Los eventos le ofrecen la posibilidad de obtener errores de tiempo de compilación que el complemento necesita ser modificado, porque algunas de las firmas de eventos han cambiado.

Usted solicitó enfoques alternativos.

Comandos:

En lugar de complementos que responden a eventos activados. Los complementos envían objetos de comando a la aplicación. Cada objeto de comando implementa una interfaz utilizada por los comandos. Cuando la aplicación necesita ejecutar una función, ejecuta todos los comandos para esa función. Esto es muy parecido a los eventos, excepto que se implementa como objetos en lugar de funciones de devolución de llamada.

Macros:

En lugar de que los complementos respondan cuando suceden cosas. Los complementos hacen que las cosas sucedan de manera proactiva. Una macro es un pequeño lenguaje de alto nivel que se ejecuta sobre la aplicación y le dice qué hacer.

Oyentes de cambio de estado:

La aplicación activa los eventos con la previsión del desarrollador. El desarrollador tiene que escribir a sabiendas el código que emite el evento. En cambio, un enfoque alternativo es hacer que los objetos se transmitan automáticamente cuando su estado interno ha cambiado. Ya sea el cambio de una propiedad u otros indicadores. Los complementos pueden escuchar estos cambios de estado específicos y reaccionar en consecuencia. La ventaja de este enfoque es que el programador no tiene que recordar transmitir eventos. Por ejemplo, puede haber un objeto Documento y el programador establece una marca para marcar que el documento debe guardarse. Este cambio de estado se transmite a los complementos de escucha, y podría haber un complemento que cambie el título del documento para incluir un asterisco.

Reactgular
fuente
2
1 para las alternativas, -1 para las definiciones y el argumento de acoplamiento (que hace existir, sino de acoplamiento es una consecuencia de las opciones de diseño, lo que le da nombre a su sistema de plugins)
55
Creo que también está haciendo suposiciones acerca de cómo un evento viaja desde el generador hasta el observador / oyente. De hecho, es al revés, los ganchos están estrechamente acoplados, mientras que los eventos no.
Ahmed Masud
3

Definitivamente eventos, permite la abstracción necesaria ya en el nivel arquitectónico.

No espere que alguien que escriba un complemento lo haga de manera documentada o de alguna manera correcta. He mantenido una API bien documentada con millones de usuarios y, por una experiencia muy dolorosa, puedo decirle que básicamente nadie lee la documentación y casi nadie usa la API correctamente.

Tome el siguiente ejemplo con ganchos: tiene un sistema donde se ejecutan 20 complementos. Uno de esos complementos llama al file_copymétodo en la forma en que está documentado y espera un resultado tal como está documentado. Pero algún otro complemento ha enganchado esa función y, por lo tanto, uno de los siguientes problemas causa un bloqueo o mal funcionamiento:

  • La función de gancho simplemente se bloquea. Todos los demás complementos se atornillan ahora, porque ya no pueden file_copy o la función funciona de manera diferente de lo esperado.
  • La entrada es correcta según la documentación, pero el otro complemento no lo espera y ofrece resultados extraños o fallas.
  • La llamada funciona bien, pero el resultado ya no es el esperado según la documentación, por lo que el complemento falla o falla.

Si hace lo mismo que anteriormente con eventos con los mismos problemas dentro de esos complementos, sucede lo siguiente:

  • La función de evento del complemento X falla, pero todas las demás funcionan bien. Pero dado que esos complementos no están relacionados, simplemente puede deshabilitar ese complemento que se bloquea mientras los demás continúan funcionando bien.
  • Su función puede manejar la entrada extraña y puede verificar adecuadamente todas las cosas posibles para cada complemento individualmente. El desarrollador del complemento ahora tiene una forma estable y confiable de probar realmente su complemento, lo que le permite estar seguro de que si funciona para él, funcionará para todos. Si un complemento proporciona una entrada incorrecta, se puede aislar a ese complemento.
  • Igualmente, el resultado puede verificarse y definirse adecuadamente en todas las circunstancias, por lo que el desarrollador del complemento tiene una respuesta estable y confiable de esa función que él / ella puede probar.
TwoThe
fuente
1

La herencia puede ser una opción.

Aparte de los ganchos, la herencia no necesita definiciones de métodos adicionales, y no hay pérdida de rendimiento por llamar al método vacío en caso de que no haya nada conectado.

Además de los eventos, la herencia tampoco necesita un código adicional para la invocación de eventos.

Sin embargo, la herencia funciona mejor si solo hay un complemento que modifica un tipo de comportamiento. Si necesita muchos complementos, el segundo debería derivarse del primero, etc., lo que no es apropiado.

Thomas Weller
fuente
-1 Porque usas Herencia y luego cambias el código de instanciación para usar tu especificación y malgastas la herencia ya que el nuevo comportamiento tiene un propósito diferente como la aplicación principal ...
SparK
0

Definitivamente eventos. Permite que su arquitectura sea más ampliable.

Imagine lo que sucederá si necesita colocar su complemento en una máquina separada, por ejemplo. Uso de eventos: solo tendrá que modificar un pequeño código de paz para que su evento se base en la red.

vpol
fuente