mvc - observer pattern java
Cuándo deberíamos usar Observer y Observable (10)
Un entrevistador me preguntó:
¿Qué es Observer
y Observable
y cuándo deberíamos usarlos?
No estaba al tanto de estos términos, así que cuando volví a casa y comencé a buscar en Google Observer
y Observable
encontré algunos puntos de diferentes recursos:
1)
Observable
es una clase yObserver
es una interfaz.2) Clase
Observable
mantener una lista de observadores.3) Cuando se actualiza un objeto Observable, invoca el método
update()
de cada uno de sus observadores para notificar que se ha modificado.
Encontré este ejemplo:
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!");
}
}
Pero no entiendo por qué necesitamos Observer
y Observable
? ¿Para qué sirven los setChanged()
y notifyObservers(message)
?
Desde Java9, ambas interfaces están en desuso, lo que significa que ya no debe usarlas. See Observer está en desuso en Java 9. ¿Qué deberíamos usar en lugar de él?
Sin embargo, aún puede obtener preguntas de la entrevista sobre ellos ...
El patrón de observador se usa cuando hay una relación de uno a varios entre los objetos, como por ejemplo si un objeto se modifica, sus objetos dependientes se notificarán automáticamente.
En términos muy simples (porque las otras respuestas lo remiten a todos los patrones de diseño oficiales de todos modos, así que mírelos para obtener más detalles):
Si desea tener una clase supervisada por otras clases en el ecosistema de su programa, diga que desea que la clase sea observable. Es decir, puede haber algunos cambios en su estado que desee transmitir al resto del programa.
Ahora, para hacer esto tenemos que llamar a algún tipo de método. No queremos que la clase Observable esté estrechamente unida a las clases que están interesadas en observarla. No le importa quién es, siempre que cumpla con ciertos criterios. (Imagine que es una estación de radio, no importa quién esté escuchando, siempre y cuando tengan una radio FM sintonizada en su frecuencia). Para lograr eso, usamos una interfaz, conocida como Observer.
Por lo tanto, la clase Observable tendrá una lista de Observadores (es decir, instancias que implementen los métodos de interfaz del Observador que pueda tener). Cada vez que quiere transmitir algo, simplemente llama al método sobre todos los observadores, uno después del otro.
Lo último para cerrar el rompecabezas es ¿cómo sabrá la clase Observable quién está interesado? Entonces la clase Observable debe ofrecer algún mecanismo para permitir a los Observadores registrar su interés. Un método como addObserver(Observer o)
internamente agrega el Observer a la lista de observadores, de modo que cuando sucede algo importante, recorre la lista y llama al respectivo método de notificación de la interfaz Observer de cada instancia en la lista.
Es posible que en la entrevista no le hayan preguntado explícitamente sobre java.util.Observer
y java.util.Observable
sino sobre el concepto genérico. El concepto es un patrón de diseño, que ofrece compatibilidad con Java directamente desde el inicio para ayudarlo a implementarlo rápidamente cuando lo necesite. Por lo tanto, sugiero que comprenda el concepto en lugar de los métodos / clases reales (que puede consultar cuando los necesite).
ACTUALIZAR
En respuesta a su comentario, la clase real java.util.Observable
ofrece las siguientes instalaciones:
Mantener una lista de instancias de
java.util.Observer
. Las nuevas instancias interesadas en ser notificadas pueden agregarse a través deaddObserver(Observer o)
y eliminarse mediantedeleteObserver(Observer o)
.Mantener un estado interno, especificando si el objeto ha cambiado desde la última notificación a los observadores. Esto es útil porque separa la parte donde dice que el
Observable
ha cambiado, desde la parte donde notifica los cambios. (Por ejemplo, es útil si tiene varios cambios y solo desea notificar al final del proceso en lugar de hacerlo en cada paso). Esto se hace a través desetChanged()
. Así que solo lo llamas cuando cambiaste algo alObservable
y quieres que el resto de losObservers
sepa.Notificar a todos los observadores que el
Observable
específico ha cambiado de estado. Esto se hace a través denotifyObservers()
. Esto comprueba si el objeto realmente ha cambiado (es decir, se realizó una llamada asetChanged()
) antes de continuar con la notificación. Hay 2 versiones, una sin argumentos y otra con un argumentoObject
, en caso de que quiera pasar información adicional con la notificación. Internamente, lo que sucede es que simplemente recorre la lista de instancias deObserver
y llama al método deupdate(Observable o, Object arg)
para cada uno de ellos. Esto le dice alObserver
que fue el Objeto Observable que cambió (podría estar observando más de uno), y elObject arg
adicional para potencialmente llevar algo de información extra (pasado a través denotifyObservers()
.
He escrito una breve descripción del patrón del observador aquí: http://www.devcodenote.com/2015/04/design-patterns-observer-pattern.html
Un fragmento de la publicación:
Patrón de observador: Establece esencialmente una relación uno a muchos entre los objetos y tiene un diseño débilmente acoplado entre los objetos interdependientes.
Definición de libro de texto: El patrón de observador define una dependencia de uno a muchos entre los objetos para que cuando un objeto cambie de estado, todos sus dependientes sean notificados y actualizados automáticamente.
Considere un servicio de notificación de alimentación, por ejemplo. Los modelos de suscripción son los mejores para comprender el patrón del observador.
Observer aka callback está registrada en Observable.
Se usa para informar, por ejemplo, sobre eventos que ocurrieron en algún momento. Se usa ampliamente en Swing, Ajax, GWT para despachar operaciones, por ejemplo, en eventos de IU (clics de botón, campos de texto cambiados, etc.).
En Swing encuentras métodos como addXXXListener (Listener l), en GWT tienes devoluciones de llamada (Async).
Como la lista de observadores es dinámica, los observadores pueden registrarse y anular el registro durante el tiempo de ejecución. También es una buena manera de desacoplar observable de los observadores, ya que se utilizan interfaces.
Si el entrevistador solicita implementar el patrón de diseño del observador sin utilizar las clases e interfaces de Observer, ¡puede usar el siguiente ejemplo simple!
MyObserver como interfaz de observador
interface MyObserver {
void update(MyObservable o, Object arg);
}
MyObservable como clase 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;
}
// ...
}
¡Tu ejemplo con MyObserver y 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);
}
}
Son parte del patrón de diseño del Observador . Por lo general, uno o más observadores se informan sobre los cambios en un observable . Es una notificación que "algo" sucedió, donde usted, como programador, puede definir qué significa "algo".
Cuando usa este patrón, desacopla las dos entidades una de otra: los observadores se vuelven conectables.
Tienes un ejemplo concreto de un Student y un MessageBoard. El Estudiante se registra al agregarse a la lista de Observadores que desean recibir notificaciones cuando se publica un Mensaje nuevo en el Tablero de Mensajes. Cuando se agrega un mensaje al MessageBoard, itera sobre su lista de observadores y les notifica que el evento ocurrió.
Piensa en Twitter. Cuando dices que quieres seguir a alguien, Twitter te agrega a su lista de seguidores. Cuando enviaron un nuevo tweet, lo ves en tu entrada. En ese caso, su cuenta de Twitter es el Observador y la persona que está siguiendo es el Observable.
La analogía podría no ser perfecta, porque es más probable que Twitter sea un Mediador. Pero ilustra el punto.
"Traté de averiguar, por qué exactamente necesitamos Observer y Observable"
Como las respuestas anteriores ya indicadas, proporcionan medios para suscribir un observador y recibir notificaciones automáticas de un observable.
Una aplicación de ejemplo donde esto puede ser útil es en el enlace de datos , digamos que tiene alguna UI que edita algunos datos, y desea que la IU reaccione cuando los datos se actualicen, puede hacer que sus datos sean observables y suscribir sus componentes de UI a los datos
Knockout.js es un MVVM javascript framework que tiene un excelente tutorial para comenzar, para ver más observables en acción. Realmente recomiendo seguir el tutorial. http://learn.knockoutjs.com/
También encontré este artículo en la página de inicio de Visual Studio 2008 ( El patrón Observer es la base del desarrollo de Model View Controller (MVC) ) http://visualstudiomagazine.com/articles/2013/08/14/the-observer-pattern-in-net.aspx
Definición
El patrón de observador se usa cuando hay una relación de uno a muchos entre objetos, como si un objeto se modifica, sus objetos dependientes se notificarán automáticamente y los cambios correspondientes se realizarán a todos los objetos dependientes.
Ejemplos
Digamos, su dirección permanente ha sido modificada, entonces debe notificar a la autoridad de pasaportes y la autoridad de la tarjeta pan. Por lo tanto, aquí la autoridad de pasaporte y la autoridad de la tarjeta pan son observadores y usted es un sujeto.
En Facebook también, si se suscribe a alguien, cada vez que se produzcan nuevas actualizaciones, se lo notificará.
Cuándo usarlo:
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.
Paso 1
Crear clase de sujeto.
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();
}
}
}
Paso 2
Crear clase de observador.
Observer.java
public abstract class Observer {
protected Subject subject;
public abstract void update();
}
Paso 3
Crear clases de observadores concretas
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() );
}
}
Etapa 4
Usa sujetos y objetos observadores concretos.
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);
}
}
Paso 5
Verifica la salida.
Primer cambio de estado: 15
Hex String: F
Cadena octal: 17
Cadena binaria: 1111
Segundo cambio de estado: 10
Hex String: A
Cadena octal: 12
Cadena binaria: 1010