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

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

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

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

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

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

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)?

Ответ 1

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

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

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

Ответ 2

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

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

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

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

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

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

UPDATE

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

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

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

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

Ответ 3

Определение

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

<сильные > Примеры

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

  • В Facebook также, если вы подписываетесь на кого-нибудь, тогда всякий раз, когда происходят новые обновления, вы будете уведомлены.

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

1. When one object changes its state,then all other dependents object must automatically change their state to maintain consistency
2. When subject doesn't know about number of observers it has.
3. When an object should be able to notify other objects without knowing who objects are.

Шаг 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

Hex String: F

Октальная строка: 17

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

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

Hex String: A

Октальная строка: 12

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

Ответ 4

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

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

Ответ 5

Обратный вызов наблюдателя a.k.a зарегистрирован в Observable.

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

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

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

Ответ 6

Если интервьюер просит реализовать шаблон проектирования 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);
  }

}

Ответ 7

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

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

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

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

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

Ответ 8

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

Отрывок из сообщения:

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

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

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

Ответ 9

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