Cosa dovrebbero usare i plugin: hook, eventi o qualcos'altro?


24

Prendi in considerazione un'app che consente ai plug-in di reagire al flusso del suo programma.

Conosco 2 modi per raggiungere questo obiettivo: ganci ed eventi

1. Ganci

Utilizzare le chiamate per svuotare le funzioni all'interno del flusso del programma principale. Queste funzioni possono essere sostituite dai plugin.

Ad esempio, Drupal CMS implementa hook disponibili per moduli e temi. Ecco un esempio di come l'hook è implementato in una funzione 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 modulo può implementare una modulename_file_copy($file, $source)funzione che verrà chiamata da module_invoke_allin file_copy. Al termine di questa funzione, file_copyriprenderà l'esecuzione.

2. Eventi

Avere gli eventi di invio dell'app, che possono essere ascoltati dai plugin. Dopo aver ricevuto un evento a cui è stato sottoscritto, un plugin intercetterà il flusso del programma ed eseguirà le operazioni necessarie.

Ad esempio, un plug-in della galleria jQuery Fotorama implementa diversi eventi . Ad esempio, ecco una parte del suo showmetodo che genera l' 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.]
  };

Uno script può ascoltare questo evento e fare qualcosa quando si attiva:

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

DOMANDA

  1. Esistono altri modi tradizionali per implementare tale comportamento dei plugin?

  2. In caso contrario, quando si dovrebbero usare gli hook e quando si dovrebbero usare gli eventi? Considerare l'obiettivo finale è rendere il codice più gestibile e leggibile, sia dal punto di vista dell'app che dal punto di vista dello sviluppatore del plug-in?

Risposte:


17

La differenza principale tra un hook e un evento è l'accoppiamento lento rispetto all'accoppiamento stretto.

Un hook è un modo generico per trasmettere che è successo qualcosa. È possibile aggiungere nuovi hook senza dover ricompilare i plug-in e tutti gli hook seguono un modello di progettazione generico. Una volta definita l'API hook non cambia, quindi è probabile che l'accoppiamento tra l'app e il plug-in non si interrompa.

Gli eventi sono più strettamente associati all'app. Gli eventi possono definire i parametri collegati all'evento e, se si modificano tali parametri, si interrompe l'API con plugin esistenti.

Entrambi raggiungono gli stessi risultati. Dipende solo da come si desidera accoppiare il plug-in all'app.

Gli hook possono offrirti un accoppiamento più dinamico che non si romperà quando vengono rilasciate nuove versioni della tua app, ma lo svantaggio è che non ricevi avvisi in fase di compilazione che i plug-in non sono più compatibili.

Gli eventi offrono la possibilità di ottenere errori in fase di compilazione che il plug-in deve essere modificato, poiché alcune firme degli eventi sono cambiate.

Hai chiesto approcci alternativi.

comandi:

Invece di plugin che rispondono ad eventi innescati. I plugin inviano oggetti comando all'applicazione. Ogni oggetto comando implementa un'interfaccia utilizzata dai comandi. Quando l'applicazione deve eseguire una funzione, esegue tutti i comandi per quella funzione. È molto simile agli eventi, tranne per il fatto che è implementato come oggetti anziché come funzioni di callback.

Macro:

Invece di plug-in che rispondono quando accadono le cose. I plugin fanno sì che le cose accadano in modo proattivo. Una macro è un piccolo linguaggio di alto livello che gira sopra l'applicazione e le dice cosa fare.

Ascoltatori di cambiamento di stato:

Gli eventi vengono attivati ​​dall'applicazione previamente pensata dallo sviluppatore. Lo sviluppatore deve scrivere consapevolmente codice che emette l'evento. Invece, un approccio alternativo è quello di far trasmettere automaticamente gli oggetti quando il loro stato interno è cambiato. O il cambio di una proprietà o altri indicatori. I plugin possono quindi ascoltare questi specifici cambiamenti di stato e reagire di conseguenza. Il vantaggio di questo approccio è che il programmatore non deve ricordarsi di trasmettere eventi. Ad esempio, potrebbe esserci un oggetto Document e il programmatore imposta un flag per contrassegnare la necessità di salvare il documento. Questo cambiamento di stato viene trasmesso ai plug-in di ascolto e potrebbe esserci un plug-in che modifica il titolo del documento per includere un asterisco.


2
+1 per le alternative, -1 per le definizioni e l'argomento di accoppiamento (che fa esistere, ma l'accoppiamento è una conseguenza di scelte progettuali, a seconda di quale nome che date al vostro sistema di plugin)

5
Penso che anche tu faccia ipotesi su come un evento viaggia dal generatore all'osservatore / ascoltatore. È un dato di fatto il contrario, i ganci sono strettamente accoppiati mentre gli eventi no.
Ahmed Masud,

3

Sicuramente eventi, consente l'astrazione necessaria già a livello architettonico.

Non aspettarti che chiunque scriva un plugin lo faccia effettivamente come documentato o in alcun modo corretto. Ho gestito un'API ben documentata con milioni di utenti e posso dirti per esperienza molto dolorosa che praticamente nessuno legge mai la documentazione e quasi nessuno usa l'API correttamente.

Prendi l'esempio seguente con gli hook: hai un sistema in cui sono in esecuzione 20 plugin. Uno di questi plugin chiama il file_copymetodo nel modo in cui è documentato e si aspetta un risultato come documentato. Ma alcuni altri plugin hanno agganciato quella funzione e quindi uno dei seguenti problemi provoca un arresto anomalo o un malfunzionamento:

  • La funzione hook si blocca semplicemente. Tutti gli altri plugin sono avvitati ora, perché non possono più file_copy o la funzione funziona in modo diverso da quanto previsto.
  • L'input è corretto in base alla documentazione, ma l'altro plug-in non lo prevede e produce risultati strani o arresti anomali.
  • La chiamata viene eseguita correttamente, ma il risultato non è più quello previsto dalla documentazione, pertanto il plug-in non riesce o si arresta in modo anomalo.

Se fai lo stesso come sopra con eventi con gli stessi problemi all'interno di quei plugin, accade quanto segue:

  • La funzione evento del plugin X si arresta in modo anomalo, ma tutti gli altri funzionano correttamente. Ma poiché quei plugin non sono correlati, puoi semplicemente disabilitare quel plugin che si arresta in modo anomalo mentre gli altri continuano a funzionare correttamente.
  • Gli input strani possono essere gestiti correttamente dalla tua funzione e puoi controllare correttamente tutte le cose possibili per ogni plugin individualmente. Lo sviluppatore di plugin ora ha un modo stabile e affidabile per testare effettivamente il suo plugin, che gli permette di essere sicuro che se funziona per lui funzionerà per tutti. Se un plugin fornisce un input errato, può essere isolato a quel plugin.
  • Allo stesso modo il risultato può essere verificato e definito correttamente in tutte le circostanze, quindi lo sviluppatore del plugin ha una risposta stabile e affidabile da quella funzione che può testare.

1

L'ereditarietà può essere un'opzione.

Oltre agli hook, l'ereditarietà non ha bisogno di ulteriori definizioni di metodo e non vi è alcuna perdita di prestazioni per la chiamata del metodo vuoto nel caso in cui non sia collegato nulla.

Oltre agli eventi, l'ereditarietà non ha bisogno di un codice aggiuntivo per l'invocazione degli eventi.

Tuttavia, l'ereditarietà funziona meglio se esiste un solo plug-in che modifica un tipo di comportamento. Se hai bisogno di molti plugin, il secondo dovrebbe derivare dal primo ecc., Il che non è appropriato.


-1 Perché usi Ereditarietà e poi cambi il codice di istanza per usare le tue specifiche e abusare dell'ereditarietà poiché il nuovo comportamento ha uno scopo diverso come l'applicazione principale ...
SparK,

0

Sicuramente eventi. Consente alla tua architettura di essere più scalabile.

Immagina cosa accadrà se, ad esempio, dovrai posizionare il plug-in su un computer separato. Utilizzo degli eventi: dovrai solo modificare una piccola quantità di codice per rendere la tua rete basata sugli eventi.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.