fbpx

Refaktoring IoT do maszyny stanów

Opublikowane przez Jerzy Wickowski w dniu

Kilka tygodni temu wspominałem o potrzebie refaktoringu aplikacji IsTableBusy. Planowałem użycie wzorca projektowego Command i Active Object. Jednak po przemyśleniach, bliżej kodu, doszedłem do wniosku, że w tym wypadku lepsze będzie użycie maszyny stanów. Poniżej przedstawiam uzasadnienie dlaczego tak oraz fragmenty kodu.

Dlaczego nie Active Object

Początkowo ta idea wydawała się być zacna i bardzo obiecująca. Jednak każdy refaktoring staram się zacząć od analizy, aby mieć pewność, że wiem co chcę osiągnąć i do jakiego punktu zmierzam. Pisałem już o tym w pierwszej poście Jak refaktorować. Po chwili refleksji i wysileniu zwojów mózgowych, gdy już miałem przed oczami ewentualną strukturę kodu. Doszedłem do wniosku, że użycie wzorca Active Object przewyższy złożoność całego, na razie dość prostego, programu.

Stany IsTableBusy

Na chwilę obecną urządzenie do IsTableBusy może znajdować się w jednym z pięciu stanów:

  • Initializing – łączenie z Wifi i ogólna konfiguracja początkowa
  • Registering – zarejestrowanie włączenia urządzenia i zapalenie diody symbolizującej aktualny stan
  • WaitingForClick – sprawdzenie, czy został kliknięty przycisk, jeżeli tak to zmiana stanu na któryś z dwóch następnych
  • UpdatingStatusToBusy – strzał do API z informacją, że stół jest zajęty i zaświecenie czerwonej diody
  • UpdatingStatusToFree – strzał do API z informacją, że stół jest wolny i zaświecenie zielonej diody

Co ostatecznie przekonało mnie, że należy wybrać prostsze rozwiązanie, bo stanów nie ma wiele, a przejścia miedzy nimi są nieskomplikowane.

Main

Moim celem było przede wszystkim uproszczenie pliku Main.cpp. Zatem po zmianach, w metodzie setup() odbywa się inicjalizacja potrzebnych obiektów wraz z pobraniem danych z konfiguracji. Natomiast w metodzie loop() powiadamiam StateHandler, żeby obsłużył aktualny stan.

StateHandler *stateHandler;
void setup()
{
   Serial.begin(9600);
   Button *button = new Button(BUTTON_TOP);
   Light *green = new Light(GREEN_LED);
   Light *red = new Light(RED_LED);
   Configuration *configuration = new Configuration();
   WifiConnector *wifiConnector = new WifiConnector();
   wifiConnector->AddConnectionData(configuration->GetWifiSsid(), configuration->GetWifiPassword());
   UrlPreparer *urlPreparer = new UrlPreparer();
   char *url = urlPreparer->PrepareUrl();
   ApiClient *apiClient = new ApiClient(url);
   stateHandler = new StateHandler(button, green, red, wifiConnector, apiClient);
}
void loop()
{
   stateHandler->handle();
}

Dzięki takiemu rozwiązaniu kod jest prosty, przejrzysty i wiadomo co robi i dlaczego. Pozostaje mi tylko odpowiezieć do znajduje się w klasie StateHandler.

StateHandler

Jest to byt, który jest odpowiedzialny za wykonanie odpowiedniej akcji dla bieżącego stanu oraz na zmianę stanu na nowy. Dzięki takiemu zabiegowi udało mi się wyeliminować wszystkie pętle z kodu, a wraz z tym znacznie uprościć zarządzanie przepływem w aplikacji. Jej główny fragment prezentuje się następująco:

void StateHandler::handle()
{
   switch (currentState)
   {
      case States::Initializing:
      {
         this->initialize();
         break;
      }
      case States::Registering:
      {
         this->registerDevice();
         break;
      }
      case States::WaitingForClick:
      {
         this->checkClick();
         break;
      }
      case States::UpdatingStatusToBusy:
      {
         this->setIsBusy(true);
         break;
      }
      case States::UpdatingStatusToFree:
      {
         this->setIsBusy(false);
         break;
      }
   }
}

Zakończenie

Uważam, że po tych zmianach kod stał się już całkiem przyjemny. Jakie jest Twoje zdanie? Czy widzisz jeszcze jakieś ciekawe opcje na lepszą wersję tego kodu? A może też się zastanawiasz nad jakimś refaktorem, ale się wahasz? W obu przypadkach koniecznie daj znać. Czekam ;).



Czy to był wartościowy artykuł? Zapisz się, a wyślę Ci dwa ebooki o czystym kodzie oraz będę informował Cię o nowych postach

0 Komentarzy

Dodaj komentarz

Twój adres email nie zostanie opublikowany.

Witryna wykorzystuje Akismet, aby ograniczyć spam. Dowiedz się więcej jak przetwarzane są dane komentarzy.

[contact-form-7 404 "Nie znaleziono"]

Zapisz się

Wyślę Ci dwa dokumenty mówiące o jakości kodu. Dodatkowo będę Cię informował o nowych postach i nowościach.