UP | HOME

Données immutables : intérêt du partage

Lorsque les données sont immutables, si dans son code on s'abstient de différencier les références par un test d'égalité (avec ==), il est licite de remplacer les fabriques par des fabriques poids plume, qui ne construisent qu'un unique objet pour une valeur donnée. En effet, dans cette situation, les références sont transparentes, autrement dit les références aux objets n'importent pas : on peut remplacer la construction d'un nouvel objet par l'utilisation d'un objet existant de même valeur (au sens d'equals).

Comment procéder ? Implémenter avec une table de hachage les fabriques remplaçant les constructeurs.

// La table de hachage
private Map<Cle, A> table = new HashMap<>();
// Calcul de la clé à partir des arguments du constructeur
// - Propriété requise : fonction injective
private Cle valeurCle(Args args) { ... }
// Fabrique remplaçant le constructeur
A creer(Args args){
  // Calcul de la clé
  Cle k = valeurCle(args);
  // Récupération dans la table de l'éventuel objet associé
  A r = table.get(k);
  if(r == null){
    // En l'absence d'objet, construction et mise en table.
    r = new A(args);
    table.put(k, r);
  }
  return r;
}

Lorsqu'on utilise une table de hachage, il est nécessaire de récrire la méthode hashCode héritée de la classe Object. On doit vérifier la propriété suivante : si deux objets de type A sont égaux au sens d'equals, il doivent avoir la même valeur de hachage. Comment calculer la valeur de hachage ? Cf. l'ouvrage Effective Java, de Joshua Bloch, qui fournit une recette simple et efficace. Noter aussi que le type des clés doit être immutable pour que la table fonctionne correctement.

Si la solution précédente fonctionne, elle possède un défaut : la table grossit mais ne se réduit jamais. Pourtant, lorsqu'un objet de type A n'est plus référencé que par la table, il pourrait être détruit (et la place qu'il occupe en mémoire récupérée). Il est possible d'autoriser cette destruction en utilisant des références faibles, comme une SoftReference ou une WeakReference. Ces références se distinguent des références habituelles, dites fortes, par leur relation avec le ramasse-miettes (le "garbage collector") : un objet référencé seulement par des références faibles peut être récupéré par le ramasse-miettes, contrairement au cas des références fortes. La différence entre les références de type SoftReference et celles de type WeakReference tient au moment où la récupération a lieu : d'une part lorsque la mémoire disponible devient insuffisante, d'autre part dès que l'objet devient récupérable. Pour implémenter une fabrique poids-plume, il est donc préférable d'utiliser des SoftReference, ce qui permet de réutiliser un objet récupérable.

Voir la fabrique d'entiers naturels du paquet session3.demo.patrons.poidsPlume.

Author: Hervé Grall
Version history: v1: 2015-11-02; v2: 2016-11-08[update]; v2: 2017-10-17[+WeakReference].
Comments or questions: Send a mail.
The webpage content is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.