L’art du design objet repose sur la détermination des rôles et responsabilités de chaque classe. Quelle classe est responsable de la gestion de telle ou telle donnée ? A qui et sous quelles conditions ces données sont-elles exposées ? Il est bon de se poser ces questions souvent et de questionner son modèle objet tout au long de sa conception.
Actuellement, la mode est aux POJOS. Depuis quelques années, depuis Hibernate et Spring, tout le monde a appris à programmer comme ça. On crée une classe, on déclare ses champs privés, et on génère des accesseurs : un coup de bouton droit dans Eclipse, et le tour est joué – easy as pie.
Le problème, c’est que ce réflexe conditionné est dangereux dans le cas des collections, car il affaiblit l’encapsulation de la classe.
Le code suivant illustre le problème.
En fournissant des accesseurs directs sur la collection d’Items, la classe Caddie expose son fonctionnement interne, et perd le contrôle de l’ajout ou de la suppression d’éléments dans le Set. Non seulement l’encapsulation est rompue, mais il devient plus difficile de changer l’implémentation de la classe, par exemple pour modifier le type de collection utilisée.
-
public class Caddie
-
{
-
private Set<Item> items = new LinkedHashSet<Item>();
-
public Set<Item> getItems()
-
{ return this.items;
-
}
-
public void setItems(Set<Item> items)
-
{ this.items = items;
-
}
-
}
La solution suivante permet de reprendre le contrôle sur la collection d’Items. Elle est basée sur deux principes :
- La collection exposée est une copie en lecture seule. Son type est Collection afin de découpler son implémentation interne de sa représentation externe.
- Des méthodes sont fournies (
addItem()
etremoveItem()
), qui permettent de gérer les Items. Mais cette fois, il est nécessaire de passer par la classe Caddie, qui reprend donc le contrôle de ses données. De plus, son implémentation est désormais masquée, améliorant son encapsulation et sa maintenabilité.
-
public class Caddie
-
{
-
private Set<Item> items = new LinkedHashSet<Item>();
-
public Collection<Item> getItems()
-
{ return Collections.unmodifiableSet(items);
-
}
-
public boolean addItem(Item item)
-
{ return items.add(item);
-
}
-
public boolean removeItem(Item item)
-
{ return items.remove(item);
-
}
-
}
La prochaine fois que vous générez des accesseurs pour vos POJOs, pensez à porter un regard critique sur leur encapsulation : ne laissez pas Eclipse réfléchir pour vous !