1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/wizardforcel-thinking-in-java-zh

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
В этом репозитории не указан файл с открытой лицензией (LICENSE). При использовании обратитесь к конкретному описанию проекта и его зависимостям в коде.
Клонировать/Скачать
16.2 观察器模式.md 8.1 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
Отправлено 11.03.2025 09:15 d56454c

16.2 Паттерн Observer

Паттерн 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 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/wizardforcel-thinking-in-java-zh.git
git@api.gitlife.ru:oschina-mirror/wizardforcel-thinking-in-java-zh.git
oschina-mirror
wizardforcel-thinking-in-java-zh
wizardforcel-thinking-in-java-zh
master