Khi nào chúng ta nên sử dụng Observer và Observable?


200

Một người phỏng vấn hỏi tôi:

Là gì ObserverObservablekhi chúng ta nên sử dụng chúng?

Tôi đã không nhận thức được các điều khoản này, vì vậy khi tôi trở về nhà và bắt đầu tìm hiểu về ObserverObservable, tôi đã tìm thấy một số điểm từ các tài nguyên khác nhau:

1) Observablelà một lớp và Observerlà một giao diện.

2) ObservableLớp duy trì một danh sách Observers.

3) Khi một Observableđối tượng được cập nhật, nó gọi update()phương thức của từng đối tượng Observerđể thông báo rằng nó bị thay đổi.

Tôi tìm thấy ví dụ này:

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

Nhưng tôi không hiểu tại sao chúng ta cần ObserverObservable? Các phương pháp setChanged()và là notifyObservers(message)gì?


Liên kết không hoạt động. @Androider Bạn có thể cung cấp liên kết cập nhật?
prateek

Nếu bạn đang sử dụng Java 6 trở lên, thì hãy thử dzone.com/articles/java-ee6-events-light weight
Ramiz Uddin

1
Tôi rất khuyên bạn nên đọc qua cuốn sách này để hiểu rõ về các mẫu thiết kế. Nó đi qua như ngớ ngẩn, nhưng nó là một công cụ học tập tuyệt vời.
Countofmontecristo

1
Mọi người xin lưu ý rằng; Observer / Observable bị phản đối trong Java 9. Các lựa chọn thay thế: stackoverflow.com/questions/46380073/
mẹo

Câu trả lời:


265

Bạn có một ví dụ cụ thể về một Sinh viên và MessageBoard. Học sinh đăng ký bằng cách thêm chính nó vào danh sách Người quan sát muốn được thông báo khi Tin nhắn mới được đăng lên MessageBoard. Khi một Tin nhắn được thêm vào MessageBoard, nó sẽ lặp lại danh sách Người quan sát của nó và thông báo cho họ rằng sự kiện đã xảy ra.

Hãy suy nghĩ Twitter. Khi bạn nói rằng bạn muốn theo dõi ai đó, Twitter sẽ thêm bạn vào danh sách người theo dõi của họ. Khi họ gửi một tweet mới, bạn sẽ thấy nó trong đầu vào của bạn. Trong trường hợp đó, tài khoản Twitter của bạn là Người quan sát và người bạn theo dõi là Người quan sát.

Sự tương tự có thể không hoàn hảo, bởi vì Twitter có nhiều khả năng là một Người hòa giải. Nhưng nó minh họa điểm.


57

Nói một cách rất đơn giản (vì các câu trả lời khác đang giới thiệu bạn đến tất cả các mẫu thiết kế chính thức, vì vậy hãy xem chúng để biết thêm chi tiết):

Nếu bạn muốn có một lớp được theo dõi bởi các lớp khác trong hệ sinh thái của chương trình của bạn, bạn nói rằng bạn muốn lớp đó có thể quan sát được. Tức là có thể có một số thay đổi trong trạng thái mà bạn muốn phát cho phần còn lại của chương trình.

Bây giờ, để làm điều này, chúng ta phải gọi một số phương thức. Chúng tôi không muốn lớp Có thể quan sát được kết hợp chặt chẽ với các lớp quan tâm đến việc quan sát nó. Nó không quan tâm nó là ai miễn là nó đáp ứng các tiêu chí nhất định. (Hãy tưởng tượng đó là một đài phát thanh, không quan tâm ai đang nghe miễn là họ có đài FM được điều chỉnh theo tần số của họ). Để đạt được điều đó, chúng tôi sử dụng một giao diện, được gọi là Người quan sát.

Do đó, lớp Observable sẽ có một danh sách các Observers (tức là các thể hiện triển khai các phương thức giao diện Observer mà bạn có thể có). Bất cứ khi nào nó muốn phát sóng một cái gì đó, nó chỉ gọi phương thức trên tất cả các quan sát viên, từng người một.

Điều cuối cùng để đóng câu đố là làm thế nào để lớp quan sát biết ai quan tâm? Vì vậy, lớp Observable phải cung cấp một số cơ chế để cho phép Người quan sát đăng ký sở thích của họ. Một phương thức như addObserver(Observer o)bên trong thêm Trình quan sát vào danh sách người quan sát, để khi có điều gì đó quan trọng xảy ra, nó sẽ lặp qua danh sách và gọi phương thức thông báo tương ứng của giao diện Người quan sát của từng phiên bản trong danh sách.

Có thể là trong cuộc phỏng vấn họ không hỏi bạn rõ ràng về java.util.Observerjava.util.Observablenhưng về khái niệm chung chung. Khái niệm này là một mẫu thiết kế, mà Java tình cờ cung cấp hỗ trợ trực tiếp ra khỏi hộp để giúp bạn thực hiện nhanh chóng khi bạn cần. Vì vậy, tôi sẽ đề nghị bạn hiểu khái niệm hơn là các phương thức / lớp thực tế (mà bạn có thể tra cứu khi bạn cần chúng).

CẬP NHẬT

Đáp lại bình luận của bạn, java.util.Observablelớp học thực tế cung cấp các phương tiện sau:

  1. Duy trì một danh sách các java.util.Observertrường hợp. Các trường hợp mới quan tâm đến việc được thông báo có thể được thêm thông qua addObserver(Observer o)và xóa qua deleteObserver(Observer o).

  2. Duy trì trạng thái bên trong, chỉ định liệu đối tượng có thay đổi kể từ thông báo cuối cùng cho người quan sát hay không. Điều này rất hữu ích vì nó tách biệt phần mà bạn nói rằng phần Observableđã thay đổi, từ phần bạn thông báo thay đổi. (Ví dụ: Nó hữu ích nếu bạn có nhiều thay đổi xảy ra và bạn chỉ muốn thông báo ở cuối quá trình chứ không phải ở mỗi bước nhỏ). Điều này được thực hiện thông qua setChanged(). Vì vậy, bạn chỉ cần gọi nó khi bạn thay đổi một cái gì đó thành Observablevà bạn muốn phần còn lại Observerscuối cùng biết về nó.

  3. Thông báo cho tất cả các nhà quan sát rằng cụ thể Observableđã thay đổi trạng thái. Điều này được thực hiện thông qua notifyObservers(). Điều này kiểm tra xem đối tượng đã thực sự thay đổi (tức là một cuộc gọi setChanged()được thực hiện) trước khi tiến hành thông báo. Có 2 phiên bản, một phiên bản không có đối số và một phiên bản có đối Objectsố, trong trường hợp bạn muốn truyền một số thông tin bổ sung với thông báo. Trong nội bộ những gì xảy ra là nó chỉ lặp qua danh sách các Observerthể hiện và gọi update(Observable o, Object arg)phương thức cho mỗi trường hợp đó. Điều này cho biết Observerđối tượng quan sát được đã thay đổi (bạn có thể quan sát nhiều hơn một) và phần bổ sung Object argđể có khả năng mang thêm một số thông tin (được truyền qua notifyObservers().


37

Định nghĩa

Mẫu quan sát được sử dụng khi có một đến nhiều mối quan hệ giữa các đối tượng, chẳng hạn như nếu một đối tượng được sửa đổi, các đối tượng phụ thuộc của nó sẽ được thông báo tự động và các thay đổi tương ứng được thực hiện cho tất cả các đối tượng phụ thuộc.

Ví dụ

  1. Giả sử, địa chỉ thường trú của bạn được thay đổi thì bạn cần thông báo cho cơ quan hộ chiếu và cơ quan cấp thẻ pan. Vì vậy, ở đây thẩm quyền hộ chiếu và thẩm quyền thẻ pan là quan sát viên và Bạn là một chủ thể.

  2. Trên Facebook cũng vậy, nếu bạn đăng ký với ai đó thì bất cứ khi nào có cập nhật mới thì bạn sẽ được thông báo.

Khi nào nên sử dụng nó:

  1. Khi một đối tượng thay đổi trạng thái, thì tất cả các đối tượng phụ thuộc khác phải tự động thay đổi trạng thái của họ để duy trì tính nhất quán

  2. Khi đối tượng không biết về số lượng người quan sát thì nó có.

  3. Khi một đối tượng sẽ có thể thông báo cho các đối tượng khác mà không cần biết đối tượng là ai.

Bước 1

Tạo lớp học môn học.

Tiêu đề

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

}

Bước 2

Tạo lớp Observer.

Observer.java

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

Bước 3

Tạo các lớp quan sát cụ thể

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

}

Bước 4

Sử dụng Đối tượng và đối tượng quan sát cụ thể.

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

}

Bước 5

Xác nhận đầu ra.

Thay đổi trạng thái đầu tiên: 15

Chuỗi lục giác: F

Chuỗi bát phân: 17

Chuỗi nhị phân: 1111

Thay đổi trạng thái thứ hai: 10

Chuỗi lục giác: A

Chuỗi bát phân: 12

Chuỗi nhị phân: 1010


giải thích độc đáo :)
roottraveller

3
Tôi nghĩ "Defination" là một lỗi đánh máy. Tôi hy vọng nó là một lỗi đánh máy.
JohnJohn

10

Chúng là một phần của mẫu thiết kế Observer . Thông thường, một hoặc nhiều obervers được thông báo về những thay đổi trong một quan sát được . Đó là một thông báo rằng "một cái gì đó" đã xảy ra, nơi bạn với tư cách là một lập trình viên có thể định nghĩa "cái gì đó" nghĩa là gì.

Khi sử dụng mẫu này, bạn tách rời cả hai thực thể với nhau - người quan sát trở nên có thể cắm được.


Tôi sẽ đánh giá cao, nếu bạn sẽ thêm lời giải thích board.changeMessage("More Homework!");trong câu trả lời của bạn, tôi có nghĩa là những gì xảy ra khi changeMessage("More Homework!");được gọi.
Ravi

9

Observer aka gọi lại được đăng ký tại Observable.

Nó được sử dụng để thông báo ví dụ về các sự kiện đã xảy ra tại một số thời điểm. Nó được sử dụng rộng rãi trong Swing, Ajax, GWT để gửi các hoạt động trên các sự kiện UI (nhấp chuột vào nút, trường văn bản đã thay đổi, v.v.).

Trong Swing bạn tìm thấy các phương thức như addXXXListener (Listener l), trong GWT bạn có các cuộc gọi lại (Async).

Vì danh sách các quan sát viên là động, các quan sát viên có thể đăng ký và hủy đăng ký trong thời gian chạy. Nó cũng là một cách tốt để tách rời quan sát từ các nhà quan sát, vì các giao diện được sử dụng.


9

Nếu người phỏng vấn yêu cầu triển khai mẫu thiết kế Observer mà không sử dụng các lớp và giao diện của Observer, bạn có thể sử dụng ví dụ đơn giản sau đây!

MyObserver là giao diện quan sát

interface MyObserver {

    void update(MyObservable o, Object arg);
}

MyObservable là lớp quan sát

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

    // ...
}

Ví dụ của bạn với MyObserver và 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);
  }

}

5

"Tôi đã cố gắng tìm hiểu, tại sao chính xác chúng ta cần Người quan sát và Quan sát"

Như các câu trả lời trước đã nêu, họ cung cấp phương tiện đăng ký một người quan sát để nhận thông báo tự động của một quan sát.

Một ứng dụng ví dụ có thể hữu ích là liên kết dữ liệu , giả sử bạn có một số UI chỉnh sửa một số dữ liệu và bạn muốn UI phản ứng khi dữ liệu được cập nhật, bạn có thể quan sát dữ liệu của mình và đăng ký các thành phần UI của bạn dữ liệu

Knockout.js là một khung javascript MVVM có một hướng dẫn bắt đầu tuyệt vời, để xem nhiều quan sát hơn trong hành động tôi thực sự khuyên bạn nên xem qua hướng dẫn. http://learn.knockoutjs.com/

Tôi cũng tìm thấy bài viết này trong trang bắt đầu của Visual Studio 2008 ( Mẫu máy chủ quan sát là nền tảng của phát triển Model View Controller (MVC) ) http://visualstudiomagazine.com/articles/2013/08/14/the-observer-potype-in -net.aspx


3

Tôi đã viết một mô tả ngắn về mẫu người quan sát ở đây: http://www.devcodenote.com/2015/04/design-potypes-observer-potype.html

Một đoạn trích từ bài viết:

Mẫu quan sát: Về cơ bản, nó thiết lập mối quan hệ một-nhiều giữa các đối tượng và có thiết kế liên kết lỏng lẻo giữa các đối tượng phụ thuộc lẫn nhau.

Định nghĩa sách giáo khoa: Mẫu quan sát xác định sự phụ thuộc một-nhiều giữa các đối tượng để khi một đối tượng thay đổi trạng thái, tất cả các phụ thuộc của nó sẽ được thông báo và cập nhật tự động.

Hãy xem xét một dịch vụ thông báo thức ăn chẳng hạn. Các mô hình đăng ký là tốt nhất để hiểu mô hình quan sát viên.


0

Mẫu quan sát được sử dụng khi có mối quan hệ một-nhiều giữa các đối tượng, chẳng hạn như nếu một đối tượng được sửa đổi, các đối tượng phụ thuộc của nó sẽ được thông báo tự động.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.