RPI LCD Dev log – Chaining (łańcuchowanie?) metod

Ten tydzień należał do ulepszeń elementów funkcyjnych menu (które to wreszcie pozwalają na sensowne wyjście z submenu do menu wyższego). Nie byłoby to tak łatwo możliwe, gdyby nie chaining metod. Okazał się on prostym rozwiązaniem, które uwalnia programistę od piekła zależności uprzykrzających korzystanie z wielopoziomowego menu. Jak to działa? Już tłumaczę.

Scenariusz

Aby dodać dwupoziomowe menu, należy stworzyć najpierw obiekt głównego menu. Następnie można zdefiniować obiekt submenu, wypełnić go kolejnymi elementami, by ostatecznie przypisać go do menu głównego. Jak jednak obsługiwać sterowanie gdy użytkownik przejdzie z poziomu głównego menu do poziomu submenu? Załóżmy że submenu dziedziczy po głównym menu i jest praktycznie identyczne pod względem metod (przynajmniej obsługi sterowania).

Rozwiązanie 1 (beznadziejne)

Najprostszym logicznie i zarazem beznadziejnym w realizacji sposobem, byłoby obliczanie na bieżąco, jakie kroki w menu czyni użytkownik. W momencie przejścia do jakiegoś menu innego poziomu trzeba by było manualnie to wykryć i odpowiednio obsłużyć:

Chyba nie muszę mówić jak potencjalnie problematycznie oraz generalnie chaotyczne i słabe jest to rozwiązanie…

Rozwiązanie 2

Innym wyjściem jest zrobienie osobnej nadklasy do sterowania całym ruchem od użytkownika, która będzie wszystko wyliczać za nas. Rozwiązanie całkiem niezłe ale niesie za sobą kilka wad:

  • dodatkowa klasa jeszcze bardziej utrudniająca obsługę
  • mniejsza elastyczność rozwiązania – jeśli autor o czymś nie pomyśli, to potem ciężko będzie to wprowadzić…
  • sporo dodatkowej pracy 🙁

Rozwiązanie 3

Rozwiązaniem, na które się zdecydowałem jest chaining metod, popularny w językach wysokiego poziomu jak Java czy PHP. Często wykorzystywany jest w wszelkiego rodzaju builderach, jak np. przykładowy builder do wysyłania maili:

Jak to działa? Każda metoda zwraca zawsze referencję do tego samego obiektu, więc możemy po niej wykonywać kolejne metody na tym samym obiekcie. I tyle, zero magii. Co to nam natomiast daje?

  • przyjemny i czytelny zapis,
  • większą kontrolę nad obiektem,
  • elastyczność,
  • (niestety wada) trzeba dbać o to, żeby użyć wszystkich elementów buildera.

Ten sam mechanizm zastosowałem we wszystkich metodach menu i submenu, natomiast w processEnter() dodałem możliwość zwracania referencji do SubMenu. Dzięki temu po przejściu z Menu do SubMenu, metoda zwraca referencje do menu niższego rzędu. Możemy to przypisać do zmiennej przechowującej poprzednie menu i problem dbania do którego (sub)menu mamy się odwoływać z eventami ruchu użytkownika mamy z głowy.

Jak wygląda przykładowe użycie:

Ot taka ciekawostka, może komuś się przyda 😉