Guava – EventBus

Wstęp

W tym wpisie wyjdziemy na chwilę ze strefy komfortu jaką zaczyna dawać nam standardowa biblioteka Javy. Jedną z bardziej popularnych bibliotek, która często upraszcza procesy lub podaje trochę inne rozwiązania znanych problemów niż JDK jest guava. To biblioteka wspierana przez google i dostarcza naprawdę olbrzymi wachlarz nowych możliwości.

Na lekcjach kodu jeszcze nie raz wrócę do tej biblioteki. Jednak dzisiaj chciałbym zaprezentować jedną z jej funkcji. Dowiesz się jak w bardzo prosty sposób zaimplementować komunikację między komponentami programu. Komunikację osiągniemy poprzez zadeklarowanie subskrybenta(-ów) i nadawcy za pomocą klasy EventBus dostarczanej właśnie przez guava.

Problem

Jeżeli jesteś na początku swojej drogi programistycznej, zapewne wiesz, że obiekty mogą się ze sobą komunikować. Właśnie na tym polega język obiektowy. Poszczególne obiekty wchodzące w skład programu wysyłają sygnały (np. zmieniając swój stan) do innych obiektów. W prostym kodzie od jakiego często zaczyna się swoją przygodę z programowaniem używamy do tego zależności. A co jeśli chcielibyśmy aby w skutek jakiegoś wydarzenia w naszym programie (np. utworzenia obiektu) inne komponenty programu zareagowały w jakiś określony sposób? Możemy po prostu wstrzyknąć zależność? Istnieje inne rozwiązanie, oparte o podejście nadawca-subskrybent.

Użycie biblioteki guava

Wstęp

Załóżmy, że piszemy program do zarządzania logistyką kolejową. Głównym domenowym obiektem jest klasa Cargo (jak poniżej):

public class Cargo {
   private String id;
   private Owner owner;
   private CargoType type;
   private int capacity;

   //konstruktor
   // gettery

   public void calculateCapacity(int currentLoad) {
       this.capacity = this.capacity - currentLoad;
   }
}

 gdzie klasa Owner to:

public class Owner {
   private String firstName;
   private int age;
}


a CargoType jest enum’em :

public enum CargoType {
   BIG,
   SMALL,
   MEDIUM
}

Założenie projektu jest takie, że każde dodanie nowego obiektu Cargo w programie powoduje zalogowanie dwóch informacji w dwóch różnych miejscach w kodzie. W jednym miejscu logujemy pojemność a w drugim rozmiar.

Użycie Maven’a

Najpierw trzeba dodać bibliotekę do zależności. W tym celu używamy menadżera zależności jakim jest np. Maven. Gdy uruchomisz projekt, który używa maven’a wtedy do twojego kodu projektu zostanie dodany plik pom.xml.

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>

   <groupId>org.example</groupId>
   <artifactId>Cargo</artifactId>
   <version>1.0-SNAPSHOT</version>
   <properties>
       <maven.compiler.source>11</maven.compiler.source>
       <maven.compiler.target>11</maven.compiler.target>
   </properties>

   <dependencies>
       <dependency>
           <groupId>com.google.guava</groupId>
           <artifactId>guava</artifactId>
           <version>30.0-jre</version>
       </dependency>
   </dependencies>


</project>

Jedyne co dodałem sam to jest element dependencies, który zawiera odwołanie do zależności biblioteki guava.

Moje IDE  (IntelliJ) automatycznie pobiera nowe zależności i udostępnia nam funkcjonalności biblioteki.

Subskrybowanie

Stworzyłem dwie klasy CargoTypeLogger oraz CargoCapacityLogger, które będą miały zadanie logować informacje o typie jak i pojemności nowo dodanego obiektu Cargo.
W tym prostym przypadku tylko wyświetlę te dane w konsoli.

public class CargoCapacityLogger {
  
   @Subscribe
   public void recordNewCargoCapacity(Cargo cargo) {
       System.out.println("Capacity subscription " +
cargo.getCapacity());
   }
}

i analogicznie logowanie typu: 

public class CargoTypeLogger {

   @Subscribe
   public void recordNewCargoType(Cargo cargo) {
       System.out.println("Type subscription " +
cargo.getType().name());
   }
}

Widzimy adnotację metody @Subscribe, która jest częścią biblioteki guava. Jest to adnotacja pozwalająca metodzie zasubskrybować się na obiekt Cargo. Pobrany obiekt można następnie poddać procesom biznesowym wewnątrz metody “przechwytującej”.

Publikacja zdarzenia

Zdarzenie o utworzeniu nowego obiektu Cargo pochodzić będzie z serwisu Cargos, który w zamyśle obsługuje wszystkie prace związane z obiektami Cargo.

public class Cargos {

   private EventBus eventBus;

   public Cargos(EventBus eventBus) {
       this.eventBus = eventBus;
   }

   public void addOwnedCargo(Owner owner, CargoType type, int capacity) {
       var cargo = new Cargo(UUID.randomUUID().toString(), owner, type, capacity);
       eventBus.post(cargo);
   }
}

Dzięki przypisanej zależności EventBus, będącej klasą dostarczoną przez guava, uzyskujemy dostęp do metody post, która jest “emiterem” wydarzenia.

Jak to EventBus by guava?

Kod jest już kompletny. Jak to powinno działać? W momencie wytworzenia nowego obiektu typu Cargo poprzez użycie metody addOwnedCargo, subskrybenci otrzymają dostęp do tego obiektu i będą mogli wywołać na nim swoje procesy.

public static void main(String[] args) {
   EventBus eventBus = new EventBus();

   Owner owner = new Owner("John", 20);
   var capacity = 500;
   var cargoType = CargoType.MEDIUM;

   CargoTypeLogger subscriber1 = new CargoTypeLogger();  //subskrybent
   CargoCapacityLogger subscriber2 = new CargoCapacityLogger(); //subskrybent
   eventBus.register(subscriber1); //rejestracja subskrybenta
   eventBus.register(subscriber2); //rejestracja subskrybenta

   Cargos cargos = new Cargos(eventBus);
   cargos.addOwnedCargo(owner, cargoType, capacity); /wytworzenie obiektu Cargo
}

Po uruchomieniu programu widzimy następujące dane w konsoli:

Type subscription MEDIUM

Capacity subscription 500

Success!!!

Podsumowanie

W bardzo prosty sposób uzyskaliśmy możliwości emitowania oraz publikowania eventów. Oddzielne klasy będące subskrybentami, po rejestracji w EventBus uzyskały dostęp do danych przesyłanych przez emiter z serwisu. 

Mam nadzieję, że zainteresowałem Ciebie nowymi możliwościami jakie otwiera dla programisty biblioteka guava

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *