Паттерн Observer
решает довольно обычную проблему: когда состояние одного объекта изменяется, требуется обновление группы других объектов. Как это можно сделать? В MVC (модель-представление-контроллер) Smalltalk'а или в эквивалентной "документ-представление" структуре, вы можете наблюдать эту проблему. У нас есть данные ("документ") и несколько представлений, таких как график (Plot
) и текстовое представление. При изменении данных, оба представления должны знать, что им следует обновиться, а именно это и делает "observer". Это очень распространенная задача, решение которой входит в стандартную библиотеку java.util
.
В Java существуют два типа объектов для реализации паттерна Observer
. Класс Observable
используется для отслеживания всех индивидуумов, которым требуется уведомление при изменении состояния — независимо от того, действительно ли произошло изменение. Если кто-то скажет: "Хорошо, всем нужно проверить себя и возможно обновиться", то класс Observable
выполнит эту задачу — вызывая метод notifyObservers()
для каждого "человека" в списке. Метод notifyObservers()
является частью базового класса Observable
.
В паттерне Observer
, могут меняться две вещи: количество наблюдаемых объектов и способ их обновления. То есть, этот паттерн позволяет одновременно изменять эти две составляющие без влияния на окружающий код.```java
//: BoxObserver.java
// Демонстрация паттерна Observer с использованием
// встроенных классов наблюдателя Java.
import java.awt.;
import java.awt.event.;
import java.util.*;
```md
// Вы должны наследовать новый тип Observable:
class BoxObservable extends Observable {
public void notifyObservers(Object b) {
// В противном случае изменения не будут распространяться:
setChanged();
super.notifyObservers(b);
}
}
public class BoxObserver extends Frame {
Observable notifier = new BoxObservable();
public BoxObserver(int grid) {
setTitle("Демонстрирует паттерн наблюдателя");
setLayout(new GridLayout(grid, grid));
for(int x = 0; x < grid; x++)
for(int y = 0; y < grid; y++)
add(new OCBox(x, y, notifier));
}
public static void main(String[] args) {
int grid = 8;
if(args.length > 0)
grid = Integer.parseInt(args[0]);
Frame f = new BoxObserver(grid);
f.setSize(500, 400);
f.setVisible(true);
f.addWindowListener(
new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
}
``````java
class OCBox extends Canvas implements Observer {
Observable notifier;
int x, y; // Расположение в сетке
Color cColor = newColor();
static final Color[] colors = {
Color.BLACK, Color.BLUE, Color.CYAN,
Color.DARK_GRAY, Color.GRAY, Color.GREEN,
Color.LIGHT_GRAY, Color.MAGENTA,
Color.ORANGE, Color.PINK, Color.RED,
Color.WHITE, Color.YELLOW
};
static final Color newColor() {
return colors[(int)(Math.random() * colors.length)];
}
OCBox(int x, int y, Observable notifier) {
this.x = x;
this.y = y;
notifier.addObserver(this);
this.notifier = notifier;
addMouseListener(new ML());
}
public void paint(Graphics g) {
g.setColor(cColor);
Dimension s = getSize();
g.fillRect(0, 0, s.width, s.height);
}
class ML extends MouseAdapter {
public void mousePressed(MouseEvent e) {
notifier.notifyObservers(OCBox.this);
}
}
public void update(Observable o, Object arg) {
OCBox clicked = (OCBox)arg;
if(nextTo(clicked)) {
cColor = clicked.cColor;
repaint();
}
}
private final boolean nextTo(OCBox b) {
return Math.abs(x - b.x) <= 1 &&
Math.abs(y - b.y) <= 1;
}
}
Если вы впервые просматриваете онлайн-документацию по `Observable`, возможно, вас слегка смутило то, что кажется возможным использовать исходный объект `Observable` для управления обновлениями. Однако это неверно; попробуйте сами — создайте объект `Observable` внутри `BoxObserver`, заменив объект `BoxObservable`. Вы заметите, что ничего не произойдет. Для того чтобы действительно добиться эффекта, необходимо наследовать от `Observable` и вызвать метод `setChanged()` где-то в коде производного класса. Этот метод устанавливает флаг `changed` (изменилось), который означает, что при вызове `notifyObservers()` все наблюдатели фактически получат уведомление.
```В приведённом выше примере `setChanged()` просто вызывается перед `notifyObservers()`, но вы можете решить, когда вызывать `setChanged()`, в зависимости от конкретной ситуации. Класс `BoxObserver` включает в себя единственный объект `Observable`, названный `notifier`. При каждом создании объекта `OCBox` он связывается с `notifier`. Внутри `OCBox` при клике мыши вызывается метод `notifyObservers()`, который передаёт выбранный объект как аргумент. Это позволяет всем коробкам, которые получили сообщение через выполнение своего метода `update()`, узнать, какой объект был выбран, и принять решение о необходимости изменения состояния.Сочетание кода в методах `notifyObservers()` и `update()` позволяет эффективно решать сложные ситуации.
В методе `notifyObservers()` может показаться, что способ получения уведомлением наблюдателями должен быть зафиксирован во время компиляции. Однако, более внимательное рассмотрение приведённого выше кода показывает, что единственным местом, где требуется использование конкретного типа `BoxObservable`, является момент создания объекта `Observable`. После этого все остальные операции используют базовый интерфейс `Observable`. Это значит, что позже можно будет изменить способ уведомления, наследуясь от других классов `Observable` и заменяя их во время выполнения программы.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )