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

22

Considera un'app che permetta ai plug-in di reagire al suo flusso di programma.

Conosco 2 modi per ottenere ciò: hook e eventi

1. Ganci

Usa le chiamate per svuotare le funzioni all'interno del flusso del programma principale. Queste funzioni possono essere sostituite dai plug-in.

Ad esempio, Drupal CMS implementa hook che sono disponibili per moduli e temi. Ecco un esempio di come viene implementato l'hook 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 funzione modulename_file_copy($file, $source) che verrà chiamata da module_invoke_all in file_copy . Al termine di questa funzione, file_copy riprenderà l'esecuzione.

2. Eventi

Avere l'app invia eventi, che possono essere ascoltati dai plugin. Dopo aver ricevuto un evento a cui è stato sottoscritto, un plug-in intercetterà il flusso del programma ed eseguirà operazioni necessarie.

Ad esempio, un plugin per galleria jQuery Fotorama implementa diversi eventi . Ad esempio, ecco una parte del suo metodo show che genera l'evento fotorama:show .

  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 plug-in?

  2. In caso negativo, quando si dovrebbero usare gli hook e quando si dovrebbero usare gli eventi? Considerare l'obiettivo finale è rendere il codice più controllabile e leggibile, sia dall'app che dal punto di vista dello sviluppatore del plugin?

posta sbichenko 04.05.2014 - 12:57
fonte

4 risposte

16

La principale differenza tra un gancio e un evento è l'accoppiamento libero rispetto all'accoppiamento stretto.

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

Gli eventi sono più strettamente accoppiati all'app. Gli eventi possono definire i parametri collegati all'evento e, se cambi questi parametri, interrompi l'API con i plugin esistenti.

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

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

Gli eventi ti offrono la possibilità di ottenere errori in fase di compilazione che il plug-in deve essere modificato, perché alcune delle firme degli eventi sono state modificate.

Hai chiesto approcci alternativi.

Comandi:

Invece dei plugin che rispondono agli eventi attivati. I plugin spingono gli oggetti comando nell'applicazione. Ogni oggetto comando implementa un'interfaccia utilizzata dai comandi. Quando l'applicazione deve eseguire una funzione, esegue tutti i comandi per quella funzione. Questo è molto simile agli eventi, tranne che è implementato come oggetti al posto delle funzioni di callback.

Macro:

Invece dei plugin che rispondono quando accadono le cose. I plugin provocano proattivamente le cose. Una macro è un piccolo linguaggio di alto livello che viene eseguito sopra l'applicazione dicendogli cosa fare.

Listener dei cambiamenti di stato:

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

    
risposta data 04.05.2014 - 15:19
fonte
3

Definitely events, consente l'astrazione necessaria già a livello di architettura.

Non aspettarti che qualcuno che scrive un plugin lo faccia in realtà come documentato o in qualsiasi modo corretto. Ho mantenuto un'API ben documentata con milioni di utenti e posso dirti da un'esperienza molto dolorosa che praticamente nessuno legge mai la documentazione e quasi nessuno usa correttamente l'API.

Prendi il seguente esempio con i ganci: hai un sistema in cui 20 plug-in sono in esecuzione. Uno di questi plugin chiama il metodo file_copy nel modo in cui è documentato e si aspetta un risultato come documentato. Ma qualche altro plugin ha agganciato quella funzione e quindi uno dei seguenti problemi causa un crash o un malfunzionamento:

  • La funzione di hook si blocca semplicemente. Tutti gli altri plugins sono fregati ora, perché non possono più file_copy o la funzione funziona diversamente da quanto previsto.
  • L'input è corretto in base alla documentazione, ma l'altro plug-in non si aspetta e fornisce risultati strani o arresti anomali.
  • La chiamata va bene, ma il risultato non è più quello che ci si aspetta in base alla documentazione, quindi il plugin fallisce o si blocca.

Se fai lo stesso come sopra con eventi con gli stessi problemi in questi plugin, succede quanto segue:

  • La funzione evento del plugin X si blocca, ma tutti gli altri funzionano bene. Ma dal momento che questi plugin non sono correlati, puoi semplicemente disabilitare quel plugin che si blocca mentre gli altri continuano a funzionare bene.
  • Un input strano può essere gestito correttamente dalla tua funzione e puoi controllare correttamente tutte le possibili cose per ogni plugin individualmente. Lo sviluppatore del plugin ora ha un modo stabile e affidabile di testare realmente il suo plugin, che gli consente di essere sicuro che se funziona per lui funzionerà per tutti. Se un plug-in fornisce input non corretti, può essere isolato per quel plug-in.
  • Allo stesso modo il risultato può essere controllato e definito correttamente in tutte le circostanze, quindi lo sviluppatore del plugin ha una risposta stabile e affidabile da quella funzione che può testare.
risposta data 11.05.2014 - 12:40
fonte
1

L'ereditarietà può essere un'opzione.

Diversamente dagli hook, l'ereditarietà non ha bisogno di definizioni di metodo aggiuntive e non ci sono perdite di prestazioni per chiamare il metodo vuoto nel caso in cui non ci sia nulla di collegato.

Oltre agli eventi, l'ereditarietà non richiede inoltre un codice aggiuntivo per il richiamo di un evento.

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

    
risposta data 10.05.2014 - 23:07
fonte
0

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

Immagina cosa succederà se, ad esempio, dovrai posizionare il tuo plug-in su una macchina separata. Utilizzo degli eventi: è sufficiente modificare una piccola parte di codice per rendere la rete degli eventi basata.

    
risposta data 13.05.2014 - 07:41
fonte