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:
- W programie wyróżniamy 2 zasadnicze części:
- część odpowiedzialną za obiekt obserwowany (interfejs Observable)
- część odpowiedzialną za obserwatorów obiektu (interfejs Observator)
- 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();
- Dodatkowo w obiekcie obserwowanym tworzona jest kolekcja obserwatorów:
- private Set<Observer> registeredObservers = new HashSet<Observer>();
- Oraz implementujemy w obiekcie obserwowanym dodatkową metodę :
- public void changeOrderStatus(OrderStatus orderStatus)
- 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());
}
}
