Ładowarki elektryczne i wzorzec Obserwator

Mieszkając w Oslo opłaca się posiadać samochód elektryczny. Pozwala on na swobodę w transporcie indywidualnym poprzez szereg udogodnień dla samochodów tego typu. Zredukowane opłaty za parking i bramki miejskie pozwalają oszczędzić sporo pieniędzy a możliwość korzystania z „buspasów” ułatwia poruszanie się w godzinach szczytu. Nic dziwnego że tak wiele ludzi zdecydowało się na zakup takiego samochodu, w tym również ja. Jest również wada a zarazem zaleta – ładowanie samochodu. Zaletą jest cena, a również możliwość ładowania samochodu we własnym garażu. Miasto posiada sieć ładowarek komunalnych usytuowanych w różnych miejscach które umożliwiają darmowe ładowanie samochodu. Czyż to nie wspaniałe? Jazda za darmo!

Tutaj pojawia się wada. Ci którzy nie posiadają własnego garażu, są skazani na korzystanie z tych ładowarek (bądź komercyjnych ładowarek szybko ładujących ale te już są płatne). Mówiąc o ładowarkach komunalnych, ich liczba nie wzrasta proporcjonalnie do liczby nowych właścicieli samochodów elektrycznych z co za tym idzie ładowarki są często zajęte. Na szczęście przychodzą aplikacje na których na mapie widać aktualny status ładowarek.

Jako że sam korzystam z tego rozwiązania, interesują mnie trzy ładowarki które znajdują się w pobliżu mojego miejsca zamieszkania. Gdy potrzebuję naładować samochód, muszę podjechać do ładowarki i zostawić samochód na całą noc i wrócić piechotą do domu. Dzięki aplikacji mogę podejrzeć czy ładowarka jest wolna ale niestety nie mam możliwości otrzymywania wiadomości kiedy ona się zwolniła. Muszę odświeżać co chwilę. Z racji dużego zapotrzebowania, taka ładowarka nie będzie długo wolna i kto najszybciej się zorientuje, może szybko zareagować i skorzystać. Już nie raz byłem w sytuacji kiedy podjeżdzałem do ładowarki i ktoś był minutę szybszy niż ja. Bywało również odwrotnie, kiedy to w momencie podłączania mojego samochodu zjawiał się inny samochód i musiał niestety zawrócić. Kto pierwszy ten lepszy.

Uważam iż aplikacja celowo nie daje możliwości powiadamiania właścicieli z wiadomych konsekwencji. Jednak jeśli by tylko była możliwość dostępu do statusu ładowarek np. poprzez API to aż prosi się o napisanie programu na własny użytek. Jest to idealny przykład do zastosowania wzorca obserwator, który w dużym uproszczeniu tutaj zaprezentuje:

Oto klasa Użytkownik Samochodu

public class CarOwner {
    private String userName;

    public CarOwner(String userName){
        this.userName =userName;
    }

    public void update (String stationId,boolean status){
        if (status==true){
            System.out.println(userName+", Charger " +stationId+" available");
        }
        if (status==false){
            System.out.println(userName+", Charger "+stationId+" occupied");
        }
    }
    public String getUserName(){
        return userName;
    }
}

Powyższa klasa posiada jedynie metodę update która przyjmuje 2 argumenty: id ładowarki oraz jej status w celu wyświetlenia komunikatu w momencie zmiany statusu ładowarki, czy jest wolna czy zajęta.

Teraz tworzymy interfejs dla ładowarek czyli obiektów obserwowanych. Oto interfejs:

public interface ChargingStation {
    void addCarUser(CarOwner owner);
    void deleteCarUser(CarOwner owner);
    void notifyUsers();
}

Interfejs stacja ładowania posiada 3 metody: dodaj użytkownika, usuń użytkownika, powiadom użytkowników. Teraz zaimplentujemy interfejs dla ładowarek komunalnych:

public class NormalChargingStation implements ChargingStation {

    ArrayList<CarOwner> owners;
    boolean status;
    String stationId;

    public NormalChargingStation(String id,boolean status){
        owners =new ArrayList<>();
        this.status= status;
        this.stationId=id;
    }

    @Override
    public void addCarUser(CarOwner owner) {
        owners.add(owner);
        System.out.println("Adding user "+owner.getUserName()+" to subscribe from "+stationId);

    }

    @Override
    public void deleteCarUser(CarOwner owner) {
        owners.remove(owner);
        System.out.println("Removing user "+owner.getUserName()+" from subscribing from "+stationId);

    }

    @Override
    public void notifyUsers() {
        Iterator<CarOwner> it = owners.iterator();
        while(it.hasNext()){
            CarOwner owner = it.next();
            owner.update(stationId,status);
        }
    }

    public void setChargerStatus(boolean status){
        this.status=status;
        System.out.println(stationId+ " status changed to "+status);
        notifyUsers();
    }
}

Normalna stacja ładowania implementuje interfejs i posiada 3 zmienne:

  1. Lista typu CarOwner zawierająca listę subskrybentów
  2. Id ładowarki
  3. status ładowarki (wartość bool).

Metoda:

  1. addCarUser – dodajemy użytkownika do listy
  2. deleteCarUser – usuwamy użytkownika z listy
  3. notifyUsers – za pomocą iteratora przechodzimy po liście i dla każdego użytkownika wywołujemy funkcję update podając argumenty
  4. setChargerStatus – metoda imitująca zachowanie ładowarki kiedy to jej status zmienia się i ustawia wartość zmiennej status.

Teraz czas na wykonanie programu:

public class Main {

    public static void main(String[] args) {
        //Tworzymy stacje ładowania
        NormalChargingStation station1= new NormalChargingStation("NS22",true);
        NormalChargingStation station2= new NormalChargingStation("SS23",true);
        //Tworzymy użytkowników
        CarOwner owner1= new CarOwner("Marek");
        CarOwner owner2 = new CarOwner("Wacek");
        //Użytkownik pierwszy zostaje dodany do listy subskrybentów dla ubu stacji:
        station1.addCarUser(owner1);
        station2.addCarUser(owner1);
        //Status stacji pierwszej zmienia się i powiadamia użytkownika:
        station1.setChargerStatus(true);
        //Status stacji drugiej zmienia się i powiadamia użytkownika:
        station2.setChargerStatus(true);
        //użytkownik nr 2 zostaje dodany do listy subksrybentów stacji drugiej
        station2.addCarUser(owner2);
        //stacja 2 zmienia status i powiadamia wszystkich subskrybentów
        station2.setChargerStatus(false);
        //Użytkownik nr 1 wypisuje się z subskrypcji ładowarki nr 1
        station1.deleteCarUser(owner1);

    }
}

A oto co pojawia sie w konsoli:

Adding user Marek to subscribe from NS22
Adding user Marek to subscribe from SS23
NS22 status changed to true
Marek, Charger NS22 available
SS23 status changed to true
Marek, Charger SS23 available
Adding user Wacek to subscribe from SS23
SS23 status changed to false
Marek, Charger SS23 occupied
Wacek, Charger SS23 occupied
Removing user Marek from subscribing from NS22

Ten prosty przykład pokazuje jak można sprawnie rozwiązać to zagadnienie.

Ładowarki elektryczne i wzorzec Obserwator

Dodaj komentarz

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