Propiedades Compartidas

Algunas veces cuando cambia una propiedad de un Bean, otros objetos podrían querer ser notificados del cambio y tomar alguna acción basándose en ese cambio. Cuando una propiedad compartida cambia, la notificación del cambio se envía a los oyentes interesados.

Un Bean que contiene una propiedad compartidas debe mantener una lista de los oyentes de la propiedad, y alertar a dichos oyentes cuando cambie la propiedad. La clase PropertyChangeSupport implementa métodos para añadir y eliminar objetos PropertyChangeListener de una lista, y para lanzar objetos PropertyChangeEvent a dichos oyentes cuando cambia la propiedad compartida. Nuestros Beans pueden descender de esta clase, o utilizar una clase interna.

Un objeto que quiera escuchar los cambios de una propiedad debe poder añadirse o eliminarse de la lista de oyentes del Bean que contiene la propiedad, y responder al método de notificación del evento que señala que la propiedad ha cambiado. Implementando el interface PropertyChangeListener el oyente puede ser añadido a la lista mantenida por el Bean de la propiedad compartida, y como implementa el método PropertyChangeListener.propertyChange(), el oyente puede responder a las notificaciones de cambio de la propiedad.

La clase PropertyChangeEvent encapsula la información del cambio de la propiedad, y es enviada desde la fuente del evento de cambio de propiedad a cada objeto de la lista de oyentes mediante el método propertyChange().

Las siguientes secciones proporcionan los detalles de la implementación de propiedades compartidas.

Implementar Propiedades Compartidas dentro de un Bean

Como ya habrás leído, un Bean que contenga propiedades compartidas deberá:

La clase PropertyChangeSupport implementa dos métodos para añadir y eliminar objetos PropertyChangeListener de una lista de oyentes, e implementa un método que dispara eventos de cambios de propiedad a cada uno de los oyentes de la lista. Nuestro Bean puede descencer de PropertyChangeSupport, o utilizarla como clase interna.

Para implementar una propiedad compartida, seguiremos estos pasos:

  1. Importaremos el paquete java.beans, esto nos da acceso a la clase PropertyChangeSupport.

  2. Ejemplarizar un objeto PropertyChangeSupport:
          private PropertyChangeSupport changes = new PropertyChangeSupport(this);
    
    Este objeto mantiene una lista de oyentes del cambio de propiedad y lanza eventos de cambio de propiedad.

  3. Implementar métodos para mantener la lista de oyentes. Como PropertyChangeSupport implementa esto métodos sólo tenemos que envolver las llamadas a los métodos del objeto soportado:
          public void addPropertyChangeListener(PropertyChangeListener l) {
            changes.addPropertyChangeListener(l);
          }
          public void removePropertyChangeListener(PropertyChangeListener l) {
            changes.removePropertyChangeListener(l);
          }
    

  4. Modificar un método de selección de la propiedad para que lance un evento de cambio de propiedad:
          public void setLabel(String newLabel) {
            String oldLabel = label;
            label = newLabel;
            sizeToFit();
            changes.firePropertyChange("label", oldLabel, newLabel);
          }
    
    Observa que setLabel() almacena el valor antiguo de label, porque los dos valores, el nuevo y el antiguo deben ser pasados a firePropertyChange().
          public void firePropertyChange(String propertyName,
                                         Object oldValue, Object newValue)
    
    firePropertyChange() convierte sus parámetros en un objeto PropertyChangeEvent, y llama a propertyChange(PropertyChangeEvent pce) de cada oyente registrado. Observa que los valores nuevo y antiguo son tratados como valores Object, por eso si los valores de la propiedad son tipos primitivos como int, se debe utilizar la versión del objeto java.lang.Integer. Observa también que el evento de cambio de propiedad se dispara después de que la propiedad haya cambiado.

Cuando el BeanBox reconoce el patrón de diseño de una propiedad compartida dentro de un Bean, se verá un interface propertyChange cuando se despliege el menú Edit|Events.

Ahora que hemos dada a nuestro Bean la habilidad de lanzar eventos cuando cambia una propiedad, el siguiente paso es crear un oyente.

Implementar Oyentes de Propiedades Compartida

Para oir los eventos de cambio de propiedad, nuestro Bean oyente debe implementar el interface PropertyChangeListener. Este interface contiene un método:
   public abstract void propertyChange(PropertyChangeEvent evt)
El Bean fuente llama a este método de notificación de todos los oyentes de su lista de oyentes.

Por eso para hacer que nuestra clase pueda oir y responder a los eventos de cambio de propiedad, debe:

  1. Implementar el interface PropertyChangeListener.
          public class MyClass implements java.beans.PropertyChangeListener,
                                                       java.io.Serializable { 
    

  2. Implementar el método propertyChange() en el oyente. Este método necesita contener el código que maneja lo que se necesita hacer cuando el oyente recibe el evento de cambio de propiedad. Por ejemplo, una llamada a un método de selección de la clase oyente: un cambio en una propiedad del Bean fuente se propaga a una propiedad del Bean oyente.

Para registrar el interés en recibir notificaciones sobre los cambios en una propiedad de un Bean, el Bean oyente llama al método de registro de oyentes del Bean fuente, por ejemplo:

button.addPropertyChangeListener(aButtonListener);
O se puede utilizar una clase adaptador para capturar el evento de cambio de propiedad, y subsecuentemente llamar al método correcto dentro del objeto oyente. Aquí tienes un ejemplo tomado de los ejemplos comentados del fichero beans/demo/sunw/demo/misc/ChangeReporter.java.
OurButton button = new OurButton();
...
PropertyChangeAdapter adapter = new PropertyChangeAdapter();
...
button.addPropertyChangeListener(adapter);
...
class PropertyChangeAdapter implements PropertyChangeListener
{
  public void propertyChange(PropertyChangeEvent e)
  {
    reporter.reportChange(e);
  }
}

Propiedades Compartida en el BeanBox

El BeanBox maneja las propiedades compartida utilizando una clase adaptador. Los Beans OurButton y ChangeReporter pueden ser utilizados para ilustrar esta técnica. Para ver como funciona, seguiremos estos pasos:
  1. Arrastar ejemplares de OurButton y de ChangeReporter al BeanBox.
  2. Seleccionar el ejemplar de OurButton y elegir el menú Edit|Events|propertyChange|propertyChange.
  3. Conectar la línea que aparece al ejemplar de ChangeReporter. Se mostrará el cuadro de diálogo EventTargetDialog.
  4. Elegir reportChange desde EventTargetDialog. Se generará y compilará la clase adaptador de eventos.
  5. Seleccionar OurButton y cambiar alguna de sus propiedades. Veras informes de cambios en ChangeReporter.

Detrás de la escena, el BeanBox genera el adaptador de eventos. Este adaptador implementa el interface PropertyChangeListener, y también genera una implementación del método propertyChange() que llama el método ChangeReporter.reportChange(). Aquí tienes el código fuente del adaptador generado:

// Automatically generated event hookup file.

package tmp.sunw.beanbox;
import sunw.demo.misc.ChangeReporter;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeEvent;

public class ___Hookup_14636f1560 implements
            java.beans.PropertyChangeListener, java.io.Serializable {

    public void setTarget(sunw.demo.misc.ChangeReporter t) {
        target = t;
    }

    public void propertyChange(java.beans.PropertyChangeEvent arg0) {
        target.reportChange(arg0);
    }

    private sunw.demo.misc.ChangeReporter target;
}

El Bean ChangeReporter no necesita implementar el interface PropertyChangeListener; en su lugar, la clase adaptador generada por el BeanBox implementa PropertyChangeListener, y el método propertyChange() del adaptador llama al método apropiado del objeto fuente (ChangeReporter).

El BeanBox pone las clases de los adaptadores de eventos en el directorio beans/beanbox/tmp/sunw/beanbox.


Ozito