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

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

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

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

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

2) Observable класс ведет список Observers.

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

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

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

10 ответов

Решение

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

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

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

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

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

Теперь, чтобы сделать это, мы должны вызвать какой-то метод. Мы не хотим, чтобы класс 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 который был наблюдаемым объектом, который изменился (вы могли наблюдать более одного), и дополнительный Object arg потенциально нести некоторую дополнительную информацию (переданную через notifyObservers(),

Определение

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

Примеры

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

  2. На 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

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

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

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

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

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

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

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

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

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

Если интервьюер просит реализовать шаблон проектирования 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 {
  public void update(MyObservable o, Object arg) {
    System.out.println("Message board changed: " + arg);
  }
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Другие вопросы по тегам