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

200

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

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

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

1) Observableэто класс и Observerинтерфейс.

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)методы для?

Ravi
источник
Ссылка не работает. @Androider Можете ли вы предоставить обновленную ссылку?
prateek
Если вы используете Java 6 или выше, попробуйте этот dzone.com/articles/java-ee6-events-lightweight
Рамиз Уддин
1
Я настоятельно рекомендую прочитать эту книгу, чтобы лучше понять шаблоны проектирования. Это выглядит глупо, но это отличный инструмент обучения.
countofmontecristo
1
Все, пожалуйста, обратите внимание, что; Observer / Observable устарела в Java 9. Альтернативы: stackoverflow.com/questions/46380073/…
eren130

Ответы:

265

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

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

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

duffymo
источник
57

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

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

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

Поэтому класс Observable будет иметь список Observers (т.е. экземпляры, реализующие методы интерфейса 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()был сделан вызов ), прежде чем приступить к уведомлению. Есть 2 версии, одна без аргументов и одна с Objectаргументом, если вы хотите передать некоторую дополнительную информацию с уведомлением. Внутренне происходит то, что он просто перебирает список Observerэкземпляров и вызывает update(Observable o, Object arg)метод для каждого из них. Это говорит о том, Observerкакой объект Observable изменился (вы могли наблюдать более одного), и дополнительный, Object argчтобы потенциально нести некоторую дополнительную информацию (пропущенную через notifyObservers().

JBX
источник
37

Определение

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

Примеры

  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

Мубарак
источник
красиво объяснил :)
roottraveller
3
Я думаю, что «Определение» является опечаткой. Я надеюсь, что это опечатка.
ДжонДжон
10

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

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

Энди
источник
Я буду признателен, если вы добавите объяснение board.changeMessage("More Homework!");в своем ответе, я имею в виду, что произойдет при changeMessage("More Homework!");вызове.
Рави
9

Наблюдатель или обратный вызов зарегистрирован на Observable.

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

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

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

Павел Соларский
источник
9

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

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

interface MyObserver {

    void update(MyObservable o, Object arg);
}

MyObservable как наблюдаемый класс

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);
  }

}
Хабиб Perwad
источник
5

«Я пытался выяснить, зачем нам нужен Observer и Observable»

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

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

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

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

Эдуардо Вада
источник
3

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

Фрагмент из поста:

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

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

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

Абхишек Джайн
источник
0

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

Свапнил шарма
источник