Wzorzec projektowy Obserwator- opis i przykład zastosowania

Problem do rozwiązania:

Chcemy przesyłać powiadomienia dotyczące zamówienia poprzez email, aplikację mobilną i sms. Zależy nam, żeby w przypadku aktualizacji statusu zamówienia wykonywać jak najmniej czynności w klasie głównej main. Dodatkowo chcemy mieć możliwość sprawnego dodawania nowych kanałów komunikacyjnych. 

Opis wzorca Obserwator:

Wzorzec projektowy obserwator stosujemy, kiedy jeden obiekt przesyła informacje poprzez wiele kanałów informacyjnych. Głównym zadaniem tego wzorca jest przekazywanie informacji o zmianie stanu obiektu innym zainteresowanym obiektom.

Schemat UML rozwiązania:

Schemat działania:

  1. W programie wyróżniamy 2 zasadnicze części:
    • część odpowiedzialną za obiekt obserwowany (interfejs Observable)
    • część odpowiedzialną za obserwatorów obiektu (interfejs Observator)
  2.  Obiekt obserwowany (w naszym przypadku jest to klasa Order) implementuje interfejs Observable i nadpisuje jego metody:
    • void registerObserver(Observer observer);
    • void unregisterObserver(Observer observer);
    • void notifyObservers();
  3. Dodatkowo w obiekcie obserwowanym tworzona jest kolekcja obserwatorów:
    • private Set<Observer> registeredObservers = new HashSet<Observer>();
  4. Oraz implementujemy w obiekcie obserwowanym  dodatkową metodę :
    • public void changeOrderStatus(OrderStatus orderStatus)
  5. Kanały komunikacyjne (w naszym przypadku są to klasy Email, MobileApp, TextMessage) implementują interfejs Observator i nadpisują jego metodę:
    • void update(Order order).
Schemat postępowania w klasie main:
  • tworzymy instancję zamówienia;
  • tworzymy instancje poszczególnych kanałów komunikacyjnych;
  • rejestrujemy obserwatorów poprzez metodę registerObserver klasy Order, przesyłając danego obserwatora jako argument funkcji, który jest dodawany do kolekcji w obiekcie;
  • zawiadamiamy obserwatorów poprzez metodę notifyObserver klasy Order, która wewnętrznie na każdym obiekcie kolekcji wywoła metodę update();
  • zmieniamy status zamówienia poprzez metodę changeOrderStatus, przesyłając status jako argument funkcji;
  • wyrejestrowywujemy obserwatorów poprzez metodę registerObserver klasy Order, przesyłając danego obserwatora jako argument funkcji, który jest usuwany z kolekcji w obiekcie;

Kod programu przed zastosowaniem wzorca:

Klasa main:

import notifications.Email;
import notifications.MobileApp;
import notifications.TextMessage;
import order.Order;
import order.OrderStatus;

public class Main {
public static void main(String[] args) {

Order order = new Order(110L, OrderStatus.ZAREJESTROWANE);

TextMessage textMessage = new TextMessage();
MobileApp mobileApp = new MobileApp();
Email email = new Email();

textMessage.updateOrderStatus(order);
mobileApp.updateOrderStatus(order);
email.updateOrderStatus(order);

}
}

Klasa Order:

package order;

public class Order {

private Long orderNumber;
private OrderStatus orderStatus;

public Order(Long orderNumber, OrderStatus orderStatus) {
this.orderNumber = orderNumber;
this.orderStatus = orderStatus;
}

public Long getOrderNumber() {
return orderNumber;
}

public void setOrderNumber(Long orderNumber) {
this.orderNumber = orderNumber;
}

public OrderStatus getOrderStatus() {
return orderStatus;
}

public void setOrderStatus(OrderStatus orderStatus) {
this.orderStatus = orderStatus;
}
}

Klasa  enum OrderStatus:

package order;

public enum OrderStatus {

ZAREJESTROWANE,
WYSLANE,
ODEBRANE
}

Klasa Email:

package notifications;

import order.Order;

public class Email {
public void updateOrderStatus (Order order){
System.out.println("Email - Zamówienie numer: " + order.getOrderNumber() + " zmieniło status na: " + order.getOrderStatus());
}
}

Klasa MobileApp:

package notifications;

import order.Order;

public class MobileApp {
public void updateOrderStatus (Order order){
System.out.println("Aplikacja mobilna - Zamówienie numer: " + order.getOrderNumber() + " zmieniło status na: " + order.getOrderStatus());
}
}

Klasa TextMessage:

package notifications;

import order.Order;

public class TextMessage {
public void updateOrderStatus (Order order){
System.out.println("SMS - Zamówienie numer: " + order.getOrderNumber() + " zmieniło status na: " + order.getOrderStatus());
}
}

Kod programu po zastosowaniu wzorca:

Klasa main:

import notifications.Email;
import notifications.MobileApp;
import notifications.TextMessage;
import order.Order;
import order.OrderStatus;

public class Main {
public static void main(String[] args) {

Order order = new Order(110L, OrderStatus.ZAREJESTROWANE);

TextMessage textMessage = new TextMessage();
MobileApp mobileApp = new MobileApp();
Email email = new Email();

order.registerObserver(textMessage);
order.registerObserver(mobileApp);
order.registerObserver(email);
order.notifyObservers();

System.out.println("------------------------------");
order.changeOrderStatus(OrderStatus.WYSLANE);

System.out.println("------------------------------");
order.unregisterObserver(email);
order.changeOrderStatus(OrderStatus.ODEBRANE);

}
}

Interfejs Observable:

package order;

import notifications.Observer;

public interface Observable {

void registerObserver(Observer observer);
void unregisterObserver(Observer observer);
void notifyObservers();
}

Klasa Order:

package order;

import notifications.Observer;

import java.util.HashSet;
import java.util.Set;

public class Order implements Observable {

private Long orderNumber;
private OrderStatus orderStatus;
private Set<Observer> registeredObservers = new HashSet<Observer>(); //kolekcja (na niej wykonujemy metody add, remove)

public Order(Long orderNumber, OrderStatus orderStatus) {
this.orderNumber = orderNumber;
this.orderStatus = orderStatus;
}

@Override
public void registerObserver(Observer observer) {
registeredObservers.add(observer);
}

@Override
public void unregisterObserver(Observer observer) {
registeredObservers.remove(observer);
}

@Override
public void notifyObservers() {
for(Observer observer : registeredObservers) {
observer.update(this);
}
}

public void changeOrderStatus(OrderStatus orderStatus) {
setOrderStatus(orderStatus);
notifyObservers();
}

//gettery i settery
public Long getOrderNumber() {
return orderNumber;
}
public void setOrderNumber(Long orderNumber) {
this.orderNumber = orderNumber;
}
public OrderStatus getOrderStatus() {
return orderStatus;
}
public void setOrderStatus(OrderStatus orderStatus) {
this.orderStatus = orderStatus;
}
}

Klasa enum OrderStatus:

package order;

public enum OrderStatus {

ZAREJESTROWANE,
WYSLANE,
ODEBRANE
}

Interfejs Observer:

package notifications;

import order.Order;

public interface Observer {

void update(Order order);
}

Klasa Email:

package notifications;

import order.Order;

public class Email implements Observer {
public void update (Order order){
System.out.println("Email - Zamówienie numer: " + order.getOrderNumber() + " zmieniło status na: " + order.getOrderStatus());
}
}

Klasa MobileApp:

package notifications;

import order.Order;

public class MobileApp implements Observer {
public void update (Order order){
System.out.println("Aplikacja mobilna - Zamówienie numer: " + order.getOrderNumber() + " zmieniło status na: " + order.getOrderStatus());
}
}

Klasa TextMessage:

package notifications;

import order.Order;

public class TextMessage implements Observer {
public void update (Order order){
System.out.println("SMS - Zamówienie numer: " + order.getOrderNumber() + " zmieniło status na: " + order.getOrderStatus());
}
}

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany. Wymagane pola są oznaczone *