Когда мы должны использовать Observer и Observable?

Интервьюер спросил меня:

Что такое Observer и Observable и когда их следует использовать?

Я не знал об этих условиях, поэтому, когда я вернулся домой и начал поискать в Google по Observer и Observable, я нашел некоторые моменты из разных ресурсов:

1) Observable - это класс, а _ 6_ - это интерфейс.

2) Класс Observable поддерживает список Observer.

3) Когда объект Observable обновляется, он вызывает метод update() каждого из своих Observer, чтобы уведомить об изменении.

Я нашел такой пример:

import java.util.Observable;
import java.util.Observer;

class MessageBoard extends Observable
{
    public void changeMessage(String message) 
    {
        setChanged();
        notifyObservers(message);
    }
}

class Student implements Observer 
{
    @Override
    public void update(Observable o, Object arg) 
    {
        System.out.println("Message board changed: " + arg);
    }
}

public class MessageBoardTest 
{
    public static void main(String[] args) 
    {
        MessageBoard board = new MessageBoard();
        Student bob = new Student();
        Student joe = new Student();
        board.addObserver(bob);
        board.addObserver(joe);
        board.changeMessage("More Homework!");
    }
}

Но я не понимаю, зачем нам Observer и Observable? Для чего нужны методы setChanged() и notifyObservers(message)?


person Ravi    schedule 06.12.2012    source источник
comment
Ссылка не работает. @Androider Можете ли вы предоставить обновленную ссылку?   -  person prateek    schedule 24.05.2015
comment
Если вы используете Java 6 или выше, попробуйте этот dzone.com/articles/java- ee6-events-lightweight   -  person Ramiz Uddin    schedule 04.07.2016
comment
Я настоятельно рекомендую прочитать эту книгу, чтобы получить хорошее представление о шаблонах проектирования. Это выглядит глупо, но это отличный инструмент для обучения.   -  person countofmontecristo    schedule 19.08.2016
comment
Пожалуйста, обратите внимание на это; Observer / Observable устарел в Java 9. Альтернативы: stackoverflow.com/questions/46380073/   -  person Eren    schedule 22.08.2019
comment
Полезно ли это sourcemaking.com/design_patterns/observer?   -  person carloswm85    schedule 05.11.2020
comment
Еще один: refactoring.guru/design-patterns/observer   -  person carloswm85    schedule 05.11.2020


Ответы (10)


У вас есть конкретный пример Студента и Доска сообщений. Студент регистрируется, добавляя себя в список Наблюдателей, которые хотят получать уведомления, когда новое Сообщение публикуется на MessageBoard. Когда сообщение добавляется на MessageBoard, оно перебирает свой список наблюдателей и уведомляет их о том, что событие произошло.

Подумайте о Twitter. Когда вы говорите, что хотите подписаться на кого-то, Twitter добавляет вас в их список подписчиков. Когда они отправили новый твит, вы увидите его в своем вводе. В этом случае ваша учетная запись Twitter является Наблюдателем, а человек, на которого вы подписаны, - Наблюдаемым.

Аналогия может быть не идеальной, потому что Twitter, скорее всего, будет посредником. Но это иллюстрирует суть.

person duffymo    schedule 06.12.2012

Проще говоря (потому что другие ответы в любом случае отсылают вас ко всем официальным шаблонам дизайна, просмотрите их для получения дополнительных сведений):

Если вы хотите иметь класс, который контролируется другими классами в экосистеме вашей программы, вы говорите, что хотите, чтобы класс был наблюдаемым. Т.е. в его состоянии могут быть некоторые изменения, которые вы хотите передать остальной части программы.

Теперь, чтобы сделать это, мы должны вызвать какой-то метод. Мы не хотим, чтобы класс Observable был тесно связан с классами, которые заинтересованы в его наблюдении. Его не волнует, кто это, если он соответствует определенным критериям. (Представьте, что это радиостанция, ей все равно, кто ее слушает, если на их частоту настроено FM-радио). Для этого мы используем интерфейс, называемый Observer.

Следовательно, класс Observable будет иметь список наблюдателей (то есть экземпляров, реализующих методы интерфейса Observer, которые могут быть у вас). Всякий раз, когда он хочет что-то транслировать, он просто вызывает метод для всех наблюдателей, одного за другим.

Последнее, что закрывает загадка, - как класс Observable узнает, кому это интересно? Таким образом, класс Observable должен предлагать некоторый механизм, позволяющий наблюдателям регистрировать свой интерес. Такой метод, как addObserver(Observer o), внутренне добавляет Observer в список наблюдателей, так что, когда происходит что-то важное, он просматривает список и вызывает соответствующий метод уведомления интерфейса Observer для каждого экземпляра в списке.

Возможно, в интервью они спросили вас не о java.util.Observer и java.util.Observable, а об общей концепции. Эта концепция представляет собой шаблон проектирования, который Java обеспечивает поддержку прямо из коробки, чтобы помочь вам быстро реализовать его, когда он вам нужен. Поэтому я бы посоветовал вам понять концепцию, а не фактические методы / классы (которые вы можете найти, когда они вам понадобятся).

ОБНОВЛЕНИЕ

В ответ на ваш комментарий фактический класс java.util.Observable предлагает следующие возможности :

  1. Ведение списка java.util.Observer экземпляров. Новые экземпляры, заинтересованные в получении уведомлений, могут быть добавлены с помощью addObserver(Observer o) и удалены с помощью deleteObserver(Observer o).

  2. Поддержание внутреннего состояния, указывающего, изменился ли объект с момента последнего уведомления наблюдателей. Это полезно, потому что оно отделяет часть, в которой вы говорите, что Observable изменилось, от части, в которой вы уведомляете об изменениях. (Например, это полезно, если у вас происходит несколько изменений, и вы хотите уведомлять только в конце процесса, а не на каждом маленьком шаге). Это делается через setChanged(). Поэтому вы просто вызываете его, когда что-то меняете в Observable, и хотите, чтобы остальная часть Observers в конце концов узнала об этом.

  3. Уведомление всех наблюдателей об изменении состояния конкретного Observable. Это делается через notifyObservers(). Это проверяет, действительно ли объект изменился (т.е. был ли сделан вызов setChanged()), прежде чем продолжить уведомление. Существует две версии: одна без аргументов, а другая с аргументом Object, на случай, если вы хотите передать дополнительную информацию с уведомлением. Внутренне происходит то, что он просто перебирает список экземпляров Observer и вызывает _ 17_ для каждого из них. Это сообщает Observer, который был измененным наблюдаемым объектом (вы могли наблюдать более одного), и дополнительному Object arg, чтобы потенциально нести некоторую дополнительную информацию (передаваемую через notifyObservers().

person jbx    schedule 06.12.2012

Определение

Шаблон наблюдателя используется, когда между объектами существует отношение «один ко многим», например, если один объект изменен, его зависимые объекты должны быть уведомлены автоматически, и соответствующие изменения выполняются для всех зависимых объектов.

Примеры

  1. Допустим, ваш постоянный адрес изменился, тогда вам нужно уведомить паспортный орган и орган управления картой. Итак, здесь паспортный орган и орган по выдаче карт являются наблюдателями, а Вы - субъектом.

  2. На Facebook также: если вы подписываетесь на кого-то, тогда всякий раз, когда появляются новые обновления, вы будете получать уведомления.

Когда это использовать:

  1. Когда один объект меняет свое состояние, все остальные зависимые объекты должны автоматически изменять свое состояние для поддержания согласованности.

  2. Когда субъект не знает о количестве наблюдателей.

  3. Когда объект должен иметь возможность уведомлять другие объекты, не зная, кто такие объекты.

Шаг 1

Создайте предметный класс.

Subject.java

  import java.util.ArrayList;
  import java.util.List;

  public class Subject {

  private List<Observer> observers 
        = new ArrayList<Observer>();
  private int state;

  public int getState() {
    return state;
  }

 public void setState(int state) {
   this.state = state;
   notifyAllObservers();
 }

   public void attach(Observer observer){
     observers.add(observer);       
   }

  public void notifyAllObservers(){
    for (Observer observer : observers) {
     observer.update();
  }
}   

}

Шаг 2

Создайте класс Observer.

Observer.java

public abstract class Observer {
   protected Subject subject;
   public abstract void update();
}

Шаг 3

Создайте конкретные классы наблюдателей

BinaryObserver.java

public class BinaryObserver extends Observer{

  public BinaryObserver(Subject subject){
     this.subject = subject;
     this.subject.attach(this);
  }

  @Override
  public void update() {
     System.out.println( "Binary String: " 
     + Integer.toBinaryString( subject.getState() ) ); 
  }

}

OctalObserver.java

public class OctalObserver extends Observer{

   public OctalObserver(Subject subject){
     this.subject = subject;
    this.subject.attach(this);
 }

  @Override
  public void update() {
    System.out.println( "Octal String: " 
    + Integer.toOctalString( subject.getState() ) ); 
  }

}

HexaObserver.java

public class HexaObserver extends Observer{

  public HexaObserver(Subject subject){
    this.subject = subject;
    this.subject.attach(this);
 }

  @Override
  public void update() {
     System.out.println( "Hex String: " 
    + Integer.toHexString( subject.getState() ).toUpperCase() ); 
}

}

Шаг 4

Используйте субъект и конкретные объекты наблюдателя.

ObserverPatternDemo.java

 public class ObserverPatternDemo {
    public static void main(String[] args) {
       Subject subject = new Subject();

       new HexaObserver(subject);
       new OctalObserver(subject);
       new BinaryObserver(subject);

       System.out.println("First state change: 15");    
       subject.setState(15);
       System.out.println("Second state change: 10");   
       subject.setState(10);
 }

}

Шаг 5

Проверьте вывод.

Первое изменение состояния: 15

Шестигранная строка: F

Восьмеричная строка: 17

Двоичная строка: 1111

Второе изменение состояния: 10

Шестнадцатеричная строка: A

Восьмеричная строка: 12

Двоичная строка: 1010

person Mubarak    schedule 13.06.2014
comment
красиво объяснил :) - person roottraveller; 12.10.2016
comment
Я считаю Defination опечаткой. Надеюсь, это опечатка. - person JohnJohn; 22.12.2016
comment
Обсуждение дешево. Практические примеры превосходны. - person carloswm85; 05.11.2020

Они являются частью шаблона проектирования Observer. Обычно один или несколько наблюдателей получают информацию об изменениях в одном наблюдаемом. Это уведомление о том, что «что-то» произошло, и вы, как программист, можете определить, что означает «что-то».

При использовании этого шаблона вы отделяете обе сущности друг от друга - наблюдатели становятся подключаемыми.

person Andy    schedule 06.12.2012
comment
Буду признателен, если вы добавите объяснение board.changeMessage("More Homework!"); в свой ответ, я имею в виду, что происходит при вызове changeMessage("More Homework!");. - person Ravi; 06.12.2012

Обратный вызов Observer a.k.a зарегистрирован в Observable.

Он используется для информирования, например, о событиях, которые произошли в определенный момент времени. Он широко используется в Swing, Ajax, GWT для диспетчерских операций, например, События пользовательского интерфейса (нажатие кнопок, изменение текстовых полей и т. Д.).

В Swing вы найдете такие методы, как addXXXListener (Listener l), в GWT у вас есть (Async) обратные вызовы.

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

person Pawel Solarski    schedule 06.12.2012

Если интервьюер просит реализовать шаблон проектирования Observer без использования классов и интерфейсов Observer, вы можете использовать следующий простой пример!

MyObserver как интерфейс наблюдателя

interface MyObserver {

    void update(MyObservable o, Object arg);
}

MyObservable как класс Observable

class MyObservable
{
    ArrayList<MyObserver> myObserverList = new ArrayList<MyObserver>();

    boolean changeFlag = false;

    public void notifyObservers(Object o)
    {
        if (hasChanged())
        {
            for(MyObserver mo : myObserverList) {
                mo.update(this, o);
            }
            clearChanged();
        }
    }


    public void addObserver(MyObserver o) {
        myObserverList.add(o);        
    }

    public void setChanged() {
        changeFlag = true;
    }

    public boolean hasChanged() {
        return changeFlag;
    }

    protected void clearChanged() {
        changeFlag = false;
    }

    // ...
}

Ваш пример с MyObserver и MyObservable!

class MessageBoard extends MyObservable {
  private String message;

  public String getMessage() {
    return message;
  }

  public void changeMessage(String message) {
    this.message = message;
    setChanged();
    notifyObservers(message);
  }

  public static void main(String[] args) {
    MessageBoard board = new MessageBoard();
    Student bob = new Student();
    Student joe = new Student();
    board.addObserver(bob);
    board.addObserver(joe);
    board.changeMessage("More Homework!");
  }
}

class Student implements MyObserver {

  @Override
  public void update(MyObservable o, Object arg) {
    System.out.println("Message board changed: " + arg);
  }

}
person Mohammed H    schedule 13.03.2014

«Я пытался разобраться, зачем нам именно Observer и Observable»

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

Одним из примеров приложения, в котором это может быть полезно, является привязка данных, допустим, у вас есть пользовательский интерфейс, который редактирует некоторые данные, и вы хотите, чтобы пользовательский интерфейс реагировал на обновление данных, вы можете сделать свои данные наблюдаемыми. , и подписать компоненты пользовательского интерфейса на данные

Knockout.js - это javascript-фреймворк MVVM, в котором есть отличное руководство по началу работы, чтобы увидеть больше наблюдаемых в действии, я действительно рекомендую пройти через это руководство. http://learn.knockoutjs.com/

Я также нашел эту статью на стартовой странице Visual Studio 2008 (Шаблон Observer является основой разработки Model View Controller (MVC)) http://visualstudiomagazine.com/articles/2013/08/14/the-observer-pattern-in-net.aspx

person Eduardo Wada    schedule 30.09.2014

Я написал здесь краткое описание шаблона наблюдателя: http://www.devcodenote.com/2015/04/design-patterns-observer-pattern.html

Отрывок из поста:

Шаблон наблюдателя: он, по сути, устанавливает отношения «один ко многим» между объектами и имеет слабосвязанный дизайн между взаимозависимыми объектами.

Определение в учебнике: шаблон наблюдателя определяет зависимость «один ко многим» между объектами, так что, когда один объект меняет состояние, все его зависимые объекты автоматически уведомляются и обновляются.

Рассмотрим, например, службу уведомлений о фидах. Модели подписки лучше всего подходят для понимания паттерна наблюдателя.

person Abhishek Jain    schedule 17.04.2015

Шаблон наблюдателя используется, когда между объектами существует связь «один ко многим», например, если один объект изменен, его зависимые объекты должны быть уведомлены автоматически.

person Swapnil Sharma    schedule 08.11.2016

Начиная с Java9, оба интерфейса устарели, а это означает, что вы больше не должны их использовать. См. Observer устарел в Java 9. Что мы должны использовать вместо него?

Тем не менее, вы все равно можете получить вопросы о них на собеседовании ...

person tkruse    schedule 06.12.2017