DZone Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

Snippets has posted 5883 posts at DZone. View Full User Profile

Beans Et Properties

12.09.2008
| 4974 views |
  • submit to reddit
        Ca faisait longtemps que je réfléchissais aux défauts des beans, d'autant plus qu'avec Swing, contrairement à JEE, le code est beaucoup plus événementiel et réactif, et surtout beaucoup plus découplé. C'est-à-dire que, dans une fenêtre, quand je modifie un champ, il faut que l'application réagisse le plus vite et le mieux possible. L'inconvénient avec tout ça, c'est que pour écrire le code de l'interface, même (et surtout, je trouve) avec des gadgets comme les <a href="http://java.sun.com/j2se/1.5.0/docs/api/java/beans/BeanInfo.html">BeanInfo</a>, on galère comme des chiens. il faut sans arrêt refaire les mêmes manipulations : créer un widget swing, lui associer un modèle, <a href="http://fr.wikipedia.org/wiki/Binding">binder</a> le modèle du composant avec le modèle de beans, brancher tous les événements. Bref, c'est chiant.

Heureusement, le monde de l'informatique est riche. Sans même parler du Java, les langages à la mode disposent de modèles de propriétés intéressants : <a href="http://msdn.microsoft.com/fr-fr/library/w86s7x04(VS.80).aspx">les propriétés C#</a> que je ne connais que de nom, <a href="http://www.ruby-doc.org/docs/beginner-fr/xhtml/ch04s02.html">les attr_accessor de Ruby</a>. Tout ça m'a donné une idée : pourquoi ne pas définir pour chaque propriété de mon bean une interface permettant d'y accéder facilement.
Tiens, prenons un bean simple :
public class Bean {
	private int value;
	
	private final transient PropertyChangeSupport support = new PropertyChangeSupport(this);
	
	public void setValue(int newValue) {
		if(value!=newValue) {
			int old = value;
			value = newValue;
			support.firePropertyChange("value", old, value);
		}
	}
	
	public int getValue() {
		return value;
	}
	
	/*
	 * Je laisse le code nécessaire à l'ajout suppression des listeners à votre imagination
	 */
}

Supposons que je définisse une interface comme ça :
public interface Property<Type extends Object> {
	public void set(Type newValue);
	public Type get();
	public void addPropertyChangeListener(PropertyChangeListener listener);
	public void removePropertyChangeListener(PropertyChangeListener listener);
}
Combien vous croyez qu'il me faudra de lignes de code pour remplacer mon bean par le suivant ?
public class Bean {
	private Property<Integer> value = new PropertyImpl<Integer>(support, "value");
	
	private final transient PropertyChangeSupport support = new PropertyChangeSupport(this);
	
	public void setValue(int newValue) {
		value.set(newValue);
	}
	
	public int getValue() {
		return value.get();
	}
	
	/*
	 * Je laisse le code nécessaire à l'ajout suppression des listeners à votre imagination
	 */
}
Ben voilà, pas beaucoup :
public class PropertyImpl<Type extends Object> {
	private Type value;
	private transient final PropertyChangeSupport support;
	private transient final String name;
	public PropertyImpl(PropertyChangeSupport support, String name) {
		this.support = support;
		this.name = name;
	}
	
	public void set(Type newValue) {
		if(value!=newValue) {
			int old = value;
			value = newValue;
			support.firePropertyChange(getName(), old, value);
		}
	}
	
	public Type get() {
		return value;
	}
	
	public void addPropertyChangeListener(PropertyChangeListener listener) {
		support.addPropertyChangeListener(getName(), listener);
	}
	
	public void removePropertyChangeListener(PropertyChangeListener listener) {
		support.removePropertyChangeListener(getName(), listener);
	}
}
Bon, la magie, c'est que grâce à Java 5 et aux <a href="http://fr.wikibooks.org/wiki/Programmation_Java_Types_génériques">types génériques</a> (et aussi un peu grâce à l'autoboxing), cet objet Property, je peux l'utiliser pour des entiers, mais aussi pour des double, des booléens, des chaînes de caractère, n'importe quel objet, en fait (le seul code qui ne soit pas compatible avec des beaux objets, c'est le value!=newValue, je le sais, mais c'est juste un exemple).

Bref, une superbe idée. Tellement belle, en fait, que quelqu'un l'a déja eu : <a href="https://bean-properties.dev.java.net/">bean-properties</a> ...
En fait, la divergence entre mon idée et bean-properties, c'est que eux utilisent une espèce de gros objet générateur-aiguillage à événements-sac de noeuds. Au lieu de ça, moi, j'utilise le PropertyChangeSupport du bean original (comme ça, je casse moins de code), et le vetoableChangeListener si je veux.
Et, surtout, je suis déja arrivé à l'étape où je génère des composants graphiques <b>facilement</b> et de manière ultra-réutilisable à partir de mes Property.
Tiens, par exemple, il me faut une ligne pour passer d'un Property<Boolean> à une JCheckBox dont le ButtonModel s'appuiera sur la Property<Boolean> pour déterminer son état sélectionné ou non. Bref, c'est la fête.    

Comments

Jean-claude Stritt replied on Fri, 2009/01/02 - 7:35pm

Intéressant comme approche, mais "PropertyImpl" ne devrait-il pas implémenter "Property" ? Pourriez-vous montrer un exemple complet de composant graphique créé de la sorte ? Merci D'avance.