Проблема. Допустим имеется некий сервер локального времени (например, считает секунды от запуска). Необходима синхронизация с ним трех различных визуальных компонентов (например, 1 - обновление тестового сообщения "прошло _ с", 2 - запуск музыкального клипа через n локальных секунд, 3) - анимация процесса движения, повторяющаяся через 20 локальных секунд).
Требуется реализовать программу в которой одни объект - выполняет некоторую задачу, а три другие отслеживают его состояния для реализации собственной функциональности в соответствии с ролями:
1. Определить интерфейс
public interface Subject {
public void notifyAllObserver();//уведомить
public void attach(IObserver obs);//добавить слушателя
public void detach(IObserver obs);//удалить слушателя
}
2. Реализовать этот интерфейс в классе TimeServer (SubjectTimer) с созданием внутреннего отсчета времени.
Для создания собственного времени можно использовать класс Timer из пакета java.util.Timer, к-й запускает задачу класса TimerTask по расписанию, определяемому параметрами метода schedule( delay). Это следует сделать в конструкторе TimeServer следующим образом:
public TimeServer() {
this.timer = new Timer();
task = new TimerTask() {
public void run() {
tick();
}
};
timer.schedule(task, delay, period);
}
Реализация метода tick() должна обязательно включать посылку оповещений наблюдателям:
private void tick(){
timeState++;
notifyAllObservers(); }
Можно предусмотреть возможность обнуления сервера и получения значения текущего локального времени
public int getState() { ...
}
public void setState(int time) { ....
}
Обязательно реализуемые методы для работы со списком наблюдателей private List<IObserver> observers = new ArrayList<IObserver>(); следующие:
public void attach(IObserver observer){
observers.add(observer);
}
public void detach(IObserver observer){
observers.remove(observer);
}
public void notifyAllObservers(){
for (IObserver observer : observers) {
observer.update(this);
}
}
public class Signal extends Observer {
int count;
int start;
String file;
Media sound;
MediaPlayer mediaPlayer;
Boolean state;
public Signal(){
this.count = 0;
this.state = false;
this.start = subject.getState();
this.file = "vivo.mp3";
this.sound = new Media(new File(file).toURI().toString());
this.mediaPlayer = new MediaPlayer(sound);
}
public void onComp(int count){
this.count = count;
this.state = true;
}
public void offComp(){
this.state = false;
mediaPlayer.stop();
}
public void delComo(Subject st){
mediaPlayer.stop();
}
@Override
public void update(Subject st) {
if (state) {
if (st.getState() == start + count) {
mediaPlayer.play();
start += count;
}
if (st.getState() == start + 2)
mediaPlayer.stop();
}
3. Определить интерфейс
public interface IObserver {
public abstract void update();
}
4. Создать три класса Component, реализующих интерфейс IObserver и предназначенных для различных визуализацией.
*) Если наблюдатель будет сам обращаться к серверу, то он должен иметь ссылку на Subject
public interface IObserver {
private Subject subject;
public abstract void update();
}
инициализация Subject может быть выполнена в конструкторе объекта-Observer
или передаваться ему в как
void update(Subject subject);
5. Создать графический интерфейс пользователя для демонстрации работы приложения, включающий
1) панель запуска сервера времени, включающий запуск и выключение отсчета локального времени, состояние (активен/неактивен)
2) три панели для отображения визуальных компонентов (Используйте наследников javafx.scene.shape.Shape) с панелями настройки
Паттерн Наблюдатель (Observer) определяет зависимость "один-ко-многим" между объектами так, что при изменении состояния одного объекта все зависящие от него объекты уведомляются и обновляются автоматически.
Паттерн Observer определяет объект Subject, хранящий данные (модель), а всю функциональность "представлений" делегирует слабосвязанным отдельным объектам Observer.
При создании наблюдатели Observer регистрируются у объекта Subject.
Когда объект Subject изменяется, он извещает об этом всех зарегистрированных наблюдателей. После этого каждый обозреватель запрашивает у объекта Subject ту часть состояния, которая необходима для отображения данных.
Рис. 1 - Диаграмма классов паттерна Наблюдатель