Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Введение в паттерны проектирования Java.doc
Скачиваний:
0
Добавлен:
01.03.2025
Размер:
170.5 Кб
Скачать

Паттерн наблюдатель

Вы знакомы с понятием подписка. Сколько людей мучаются от бесконечных SMS, посылаемых различными магазинами, банками и т.д. о проходящих у них акциях, распродажах, кредитах. Эта ситуация описывается паттерном наблюдатель.

У нас есть наблюдаемый объект – магазин и множество наблюдателей за этим магазином – владельцы мобильных телефонов. Как только в магазине возникает какое-то неординарное событие (распродажа, акция, скидки), владельцы телефонов получают сообщение об этом событии.

Создадим два интерфейса Observer и Observable. Метод update интерфейса Observer предназначен для передачи сообщения клиентам. Методы registerObserver и removeObserver интерфейса Observable предназначены для регистрации и удаления клиентов магазина. Метод notifyObservers служит для уведомления клиентов о различных событиях в магазине.

package observer;

public interface Observer {

public void update (String sms);

}

package observer;

public interface Observable {

public void registerObserver(Observer o);

public void removeObserver(Observer o);

public void notifyObservers();

}

Класс Shop (магазин) наследует интерфейс Observable(доступный для наблюдения) и содержит список всех клиентов магазина (observers), дату очередной акции магазина (date) и посылаемое клиенту сообщение (message). Метод sendMessage создает сообщение, приписывая к сообщению текущую дату. При каждом изменении переменной message вызывается метод notifyObservers, который рассылает сообщение всем подписчикам, т.е. клиентам, зарегистрированным методом registerObserver.

package observer;

import java.util.ArrayList;

import java.util.Date;

public class Shop implements Observable{

Date date;

String message;

private ArrayList<Observer> observers = new ArrayList<Observer>();

void setDate(){

date = new Date();

}

String sendMessage(){

setDate();

return message+date;

}

void setMessage(String sms){

message= sms;

notifyObservers();

}

public void registerObserver(Observer o) {

observers.add(o);

}

public void removeObserver(Observer o) {

int i = observers.indexOf(o);

if (i>=0) observers.remove(i);

}

public void notifyObservers() {

for (Observer observer : observers){

observer.update(sendMessage());

}

}

}

Класс клиент Client наследует интерфейс Observer и содержит список всех сообщений, полученных клиентом (sms). В методе update очередное сообщение добавляется в список полученных sms. В методе disply выводятся все сообщения присланные клиенту.

package observer;

import java.util.ArrayList;

public class Client implements Observer {

ArrayList<String> sms;

String name;

Client(String name){

sms=new ArrayList<String>();

this.name = name;

}

public void update(String str) {

sms.add(str);

}

void disply(){

for(String x:sms)

System.out.println("Client "+name+" receive the message "+x);

}

}

Теперь необходимо создать магазин и его клиентов. Каждый клиент регистрируется в магазине - magazine.registerObserver(client[i]). Затем всем клиентам рассылаются сообщения с разной датой magazine.setMessage("Sale "). Демонстрируем все полученные клиентами сообщения

for(int i=0;i<4;i++){

client[i].disply();

}

package observer;

public static void main(String[] args) throws InterruptedException {

Shop magazine = new Shop();

Client [] client = new Client[4];

for(int i=0;i<4;i++){

client[i] = new Client("Cl "+i);

magazine.registerObserver(client[i]);

}

for(int i=0;i<5;i++){

Thread.sleep(1000);

magazine.setMessage("Sale ");

}

for(int i=0;i<4;i++){

client[i].disply();

}

}

}

В java.util имеется реализация наблюдателя и наблюдаемого объекта – интерфейс java.util .observer и класс java.util.observable. Интерфейс содержит метод update, а наблюдаемый объект может добавлять /удалять наблюдателей методами addObserver/deleteObserver. Также наблюдаемый объект сообщает наблюдателям о совершенных изменениях методом notifyObservers. Перед вызовом этого метода необходимо сообщить о том, что наблюдаемые объекты изменились - setChanged. Метод setChanged полезен в некоторых случаях. Например, изменение наблюдаемых параметров может происходить очень часто - раз в 10 милисекунд, а отражать это изменение нужно раз в секунду, тогда вызовом метода setChanged эта проблема решается.

Рассмотрим простой пример реализации наблюдателя с использованием java.util.

Пусть у нас имеется наблюдаемый объект TestObservable. Этот объект содержит только од ну переменную – строку name. Метод modify утверждает, что объект TestObservable изменился. Понятно, что данный объект изменяется только при создании.

public class TestObservable extends java.util.Observable {

private String name = "";

public TestObservable(String name) {

this.name = name;

}

public void modify() {

setChanged();

}

public String getName() {

return name;

}

}

Наблюдатель – экземпляр класса TestObserver, наследующий интерфейс java.util.Observable, перегружает метод update. В методе update используется объект типа Observable и объект типа Object. Вызвавший update объект «о» предоставляет метод getName для доступа к наблюдаемой строке name. Также в функции update доступен объект, переданный в качестве параметра функции notifyObservers объекта типа Observable . В данном случае таким параметром является строка.

public class TestObserver implements java.util.Observer {

private String name = "";

public TestObserver(String name) {

this.name = name;

}

public void update(java.util.Observable o,Object arg) {

String str = "Called update of " + name;

str += " from " + ((TestObservable)o).getName();

str += " with argument " + (String)arg;

System.out.println(str);

}

}

Рассмотрим реализацию паттерна наблюдатель. В функции main создаются объекты:

to – наблюдаемый объект,

о1 - наблюдатель Observer 1,

о2 - наблюдатель Observer 2.

Вызов метода addObserver для объекта to to.addObserver(o1) и to.addObserver(o2) назначает наблюдателей объекта to. Вызов метода modify, устанавливает состояние – «наблюдаемый объект был изменен». После этого notifyObservers сообщает наблюдателям об изменении наблюдаемого объекта.

public class Test {

public Test() {

}

public static void main(String[] args) {

Test test = new Test();

TestObservable to = new TestObservable("Observable");

TestObserver o1 = new TestObserver("Observer 1");

TestObserver o2 = new TestObserver("Observer 2");

to.addObserver(o1);

to.addObserver(o2);

to.modify();

to.notifyObservers("Notify argument");

}

}

В качестве упражнения напишите пример с рассылкой сообщений с использованием java.util.observer и класс java.util.observable.