Czego powinny używać wtyczki: haczyki, wydarzenia lub coś innego?

24

Rozważ aplikację, która pozwala wtyczkom reagować na przebieg programu.

Znam 2 sposoby na osiągnięcie tego: haczyki i wydarzenia

1. Haki

Użyj wywołań, aby opróżnić funkcje wewnątrz głównego programu. Funkcje te można zastąpić za pomocą wtyczek.

Na przykład Drupal CMS implementuje zaczepy dostępne dla modułów i motywów. Oto przykład implementacji hooka w funkcji 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;
    // ...
}

Moduł może implementować modulename_file_copy($file, $source)funkcję, która zostanie wywołana przez module_invoke_allin file_copy. Po zakończeniu tej funkcji file_copywznawia wykonywanie.

2. Wydarzenia

Niech aplikacja wysyła zdarzenia, które mogą być odsłuchiwane przez wtyczki. Po otrzymaniu zdarzenia, które subskrybuje, wtyczka przechwytuje przebieg programu i wykonuje niezbędne operacje.

Na przykład wtyczka galerii jQuery Fotorama realizuje kilka zdarzeń . Jako przykład, oto część jego showmetody, która uruchamia fotorama:showzdarzenie.

  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.]
  };

Skrypt może nasłuchiwać tego zdarzenia i robić coś po jego uruchomieniu:

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

PYTANIE

  1. Czy istnieją inne główne sposoby implementacji takiego zachowania wtyczek?

  2. Jeśli nie, to kiedy należy użyć haczyków, a kiedy zdarzeń? Biorąc pod uwagę ostateczny cel, to uczynienie kodu łatwiejszym w utrzymaniu i czytelnym, zarówno z perspektywy aplikacji, jak i twórcy wtyczek?

sbichenko
źródło

Odpowiedzi:

17

Główną różnicą między hakiem a zdarzeniem jest luźne połączenie w stosunku do ciasnego połączenia.

Hak to ogólny sposób na przekazanie informacji o tym, że coś się wydarzyło. Możesz dodawać nowe haki bez konieczności ponownej kompilacji wtyczek, a wszystkie haki są zgodne z ogólnym wzorem. Po zdefiniowaniu interfejsu API hooka nie zmienia się, więc połączenie między aplikacją a wtyczką prawdopodobnie nie zostanie zerwane.

Zdarzenia są ściślej powiązane z aplikacją. Zdarzenia mogą definiować parametry dołączone do zdarzenia, a jeśli zmienisz te parametry, zepsujesz interfejs API za pomocą istniejących wtyczek.

Oba osiągają takie same wyniki. To zależy tylko od tego, jak chcesz połączyć wtyczkę z aplikacją.

Haki mogą zaoferować bardziej dynamiczne sprzężenie, które prawdopodobnie nie ulegnie zerwaniu po wydaniu nowych wersji aplikacji, ale wadą jest brak ostrzeżeń czasowych kompilacji, że wtyczki nie są już kompatybilne.

Zdarzenia oferują możliwość uzyskania błędów czasu kompilacji, które wymagają modyfikacji wtyczki, ponieważ niektóre sygnatury zdarzeń uległy zmianie.

Poprosiłeś o alternatywne podejście.

Polecenia:

Zamiast wtyczek reagujących na wyzwalane zdarzenia. Wtyczki wypychają obiekty poleceń do aplikacji. Każdy obiekt polecenia implementuje interfejs używany przez polecenia. Gdy aplikacja musi wykonać funkcję, uruchamia wszystkie polecenia dla tej funkcji. Jest to bardzo podobne do zdarzeń, z tym wyjątkiem, że jest implementowane jako obiekty zamiast funkcji wywołania zwrotnego.

Makra:

Zamiast wtyczek reagujących na to, co się dzieje. Wtyczki proaktywnie powodują, że coś się dzieje. Makro to mały język wysokiego poziomu, który działa nad aplikacją i informuje ją, co ma robić.

Odbiorniki zmiany stanu:

Zdarzenia są wywoływane przez aplikację, a deweloper rozważa to z góry. Deweloper musi świadomie napisać kod, który wyda zdarzenie. Zamiast tego alternatywnym podejściem jest automatyczne nadawanie obiektów po zmianie ich stanu wewnętrznego. Zmiana właściwości lub inne wskaźniki. Wtyczki mogą następnie nasłuchiwać określonych zmian stanu i odpowiednio reagować. Zaletą tego podejścia jest to, że programista nie musi pamiętać o transmisji wydarzeń. Na przykład może istnieć obiekt Document, a programista ustawia flagę oznaczającą konieczność zapisania dokumentu. Ta zmiana stanu jest transmitowana do nasłuchujących wtyczek, a może istnieć wtyczka, która zmienia tytuł dokumentu na gwiazdkę.

Reactgular
źródło
2
+1 dla alternatyw, -1 dla definicji i argumentacji sprzęgła (co robi istnieją, ale sprzęgło jest konsekwencją wyborów projektowych, w zależności od nazwy podać do systemu wtyczek)
5
Wydaje mi się, że przyjmujesz również założenia, w jaki sposób zdarzenie przemieszcza się z generatora do obserwatora / słuchacza. W rzeczywistości jest odwrotnie, haki są ściśle powiązane, podczas gdy zdarzenia nie.
Ahmed Masud
3

Zdecydowanie wydarzenia pozwalają na niezbędną abstrakcję już na poziomie architektonicznym.

Nie oczekuj, że ktokolwiek pisze wtyczkę, robi to w sposób udokumentowany lub w jakikolwiek sposób poprawny. Utrzymuję dobrze udokumentowane API z milionami użytkowników i mogę powiedzieć z bardzo bolesnego doświadczenia, że ​​w zasadzie nikt nigdy nie czyta dokumentacji i prawie nikt nie używa poprawnie API.

Weź przykład z hakami: Masz system, w którym działa 20 wtyczek. Jedna z tych wtyczek wywołuje file_copymetodę w sposób, w jaki jest udokumentowana i oczekuje wyniku zgodnie z dokumentacją. Ale niektóre inne wtyczki podłączyły tę funkcję i dlatego jeden z następujących problemów powoduje awarię lub nieprawidłowe działanie:

  • Funkcja zaczepu po prostu ulega awarii. Wszystkie inne wtyczki są teraz wkręcone, ponieważ nie mogą już file_copy lub funkcja działa inaczej niż oczekiwano.
  • Dane wejściowe są prawidłowe na podstawie dokumentacji, ale druga wtyczka nie oczekuje tego i zapewnia dziwne wyniki lub awarie.
  • Wywołanie działa poprawnie, ale wynik nie jest zgodny z oczekiwaniami zgodnie z dokumentacją, więc wtyczka nie działa lub ulega awarii.

Jeśli zrobisz to samo co powyżej w przypadku zdarzeń z tymi samymi problemami w tych wtyczkach, dzieje się tak:

  • Funkcja zdarzenia wtyczki X ulega awarii, ale wszystkie inne działają poprawnie. Ale ponieważ te wtyczki nie są ze sobą powiązane, możesz po prostu wyłączyć tę awarię wtyczki, podczas gdy inne nadal działają dobrze.
  • Dziwne wejście może być poprawnie obsługiwane przez twoją funkcję i możesz poprawnie sprawdzić wszystkie możliwe rzeczy dla każdej wtyczki osobno. Twórca wtyczek ma teraz stabilny i niezawodny sposób testowania wtyczki, co pozwala mu mieć pewność, że jeśli zadziała dla niego, będzie działać dla wszystkich. Jeśli jedna wtyczka zawiera nieprawidłowe dane wejściowe, można ją odizolować od tej jednej wtyczki.
  • Podobnie wynik można sprawdzić i poprawnie zdefiniować we wszystkich okolicznościach, dzięki czemu twórca wtyczki ma stabilną i niezawodną odpowiedź od tej funkcji, którą może przetestować.
TwoThe
źródło
1

Dziedziczenie może być opcją.

Poza chwytaniem dziedziczenie nie wymaga dodatkowych definicji metod i nie ma utraty wydajności w przypadku wywoływania pustej metody, na wypadek gdyby nic się nie podłączyło.

Oprócz zdarzeń dziedziczenie również nie wymaga dodatkowego kodu do wywołania zdarzenia.

Jednak dziedziczenie działa najlepiej, jeśli tylko jedna wtyczka modyfikuje jeden typ zachowania. Jeśli potrzebujesz wielu wtyczek, drugi musiałby pochodzić z pierwszego itd., Co nie jest właściwe.

Thomas Weller
źródło
-1 Ponieważ korzystasz z Dziedziczenia, a następnie zmieniasz kod instancji, aby używać specyfikacji i niewłaściwie używasz dziedziczenia, ponieważ nowe zachowanie ma inny cel niż główna aplikacja ...
SparK
0

Zdecydowanie wydarzenia. Pozwala to na większą skalowalność architektury.

Wyobraź sobie, co się stanie, jeśli na przykład będziesz musiał umieścić wtyczkę na osobnym komputerze. Korzystanie ze zdarzeń - wystarczy zmodyfikować niewielki spokój kodu, aby Twoje wydarzenia były oparte na sieci.

vpol
źródło