Ostatnim z wzorców opisywanych w tej serii będzie wzorzec obserwator. Standardowo przyjrzyjmy się pierw definicji tego wzorca.
Wzorzec obserwator definiuje pomiędzy obiektami zależność jeden-do-wielu w taki sposób, że kiedy wybrany obiekt zmienia swój stan, to wszystkie jego obiekty zależne zostają o tym powiadomione i automatycznie zaktualizowane.
Eric Freeman, Elisabeth Freeman, Bert Bates, Kathy Sierra – „Rusz głową! Wzorce Projektowe”
Wzorzec obserwator najlepiej zrozumieć na podstawie newslettera, działa on bardzo podobnie. Gdy ktoś zapisuje swój e-mail do jakiegoś newslettera dostaje jego nowe wydanie co miesiąc na swoją skrzynkę pocztową. Dzieję się to do tego momentu póki ktoś nie zrezygnuje z subskrypcji takiego newslettera. Na takiej samej zasadzie działa wzorzec obserwator, stąd ta nazwa zależności jeden-do-wielu, czyli jest jeden obiekt obserwowany (inaczej zwany Podmiot) w domyśle można powiedzieć, że jest to newsletter oraz wielu obiektów obserwujących, czyli każdy użytkownik newslettera z aktywną subskrypcją. Przyjrzyjmy się diagramowi klas wzorca obserwator.

Jak widzimy mamy zdefiniowane dwa interfejsy: Podmiot oraz Obserwator. Interfejsy te implementują odpowiednie klasy obserwowane (Podmiot) i obserwujące. Widzimy, że Podmiot posiada takie metody jak rejestracja obserwatora, usuniecie obserwatora oraz powiadomienie obserwatorów, a obserwator ma metodę aktualizacji. Poniżej stworzyłem przykładowy kod aplikacji opartej na wzorcu Obserwator, aby lepiej zobrazować jego działanie. Jest to aplikacja śledząca wyniki meczów na żywo.
- W pierwszym kroku tworzymy interfejs Podmiotu oraz Obserwatora.
public interface Podmiot {
public void dodajObserwatora(Obserwator obserwator);
public void usunObserwatora(Obserwator obserwator);
public void powiadomObserwatorow();
}
public interface Obserwator {
public void aktualizacja(String mecz1,String mecz2, String mecz3);
}
2. Kolejnym etapem to stworzenie klasy Podmiotu oraz Obserwatora
public class BazaMeczy implements Podmiot{
private ArrayList obserwatorzy;
private String mecz1;
private String mecz2;
private String mecz3;
public BazaMeczy(){
obserwatorzy = new ArrayList();
}
@Override
public void dodajObserwatora(Obserwator obserwator) {
obserwatorzy.add((obserwator));
}
@Override
public void usunObserwatora(Obserwator obserwator) {
int i = obserwatorzy.indexOf(obserwator);
if(i >= 0){
obserwatorzy.remove(i);
}
}
@Override
public void powiadomObserwatorow() {
for(int i = 0; i < obserwatorzy.size(); i++){
Obserwator obserwator = (Obserwator) obserwatorzy.get(i);
obserwator.aktualizacja(mecz1, mecz2, mecz3);
}
}
public void zmianaWynikow(String mecz1, String mecz2, String mecz3){
this.mecz1 = mecz1;
this.mecz2 = mecz2;
this.mecz3 = mecz3;
System.out.println("Nastapila zmiana wynikow meczy...");
powiadomObserwatorow();
}
}
public class AplikacjaMeczowa implements Obserwator{
private Podmiot bazaMeczy;
private String mecz1;
private String mecz2;
private String mecz3;
public AplikacjaMeczowa(Podmiot bazaMeczy){
this.bazaMeczy = bazaMeczy;
bazaMeczy.dodajObserwatora(this);
}
@Override
public void aktualizacja(String mecz1, String mecz2, String mecz3) {
this.mecz1 = mecz1;
this.mecz2 = mecz2;
this.mecz3 = mecz3;
wyswietlWyniki();
}
public void wyswietlWyniki(){
System.out.println(">>> Mecz Pierwszy <<<");
System.out.println(mecz1);
System.out.println(">>> Mecz Drugi <<<");
System.out.println(mecz2);
System.out.println(">>> Mecz Trzeci <<<");
System.out.println(mecz3);
}
}
3. Ostatni etap to przetestowanie działania aplikacji.
public class Test {
public static void main (String[] args){
BazaMeczy bazaMeczy = new BazaMeczy();
AplikacjaMeczowa aplikacjaMeczowa = new AplikacjaMeczowa(bazaMeczy);
bazaMeczy.zmianaWynikow("Polska 0:0 Niemcy","Anglia 0:0 Wlochy", "Holandia 0:0 Hiszpania");
bazaMeczy.zmianaWynikow("Polska 1:0 Niemcy","Anglia 0:0 Wlochy", "Holandia 1:0 Hiszpania");
bazaMeczy.zmianaWynikow("Polska 2:0 Niemcy","Anglia 0:1 Wlochy", "Holandia 1:0 Hiszpania");
}
}

Podsumowując wzorzec Obserwator:
- wzorzec definiuje relacje jeden-do-wielu
- obiekty obserwowane (Podmiot) przesyłają powiadomienia i aktualizacje do obiektów obserwujących przy użyciu jednego interfejsu
- obiekty obserwujące są luźno powiązane z obiektem obserwowanym
- minusem jest to, że Obserwator powiadomiony o zmianie sam musi dojść do tego co się zmieniło w obiekcie obserwowanym, a zzasami takie sprawdzenie może nie być trywialne
Źródła:
- Eric Freeman, Elisabeth Freeman, Bert Bates, Kathy Sierra – „Rusz głową! Wzorce Projektowe”