Objet null (patron de conception)
Dans la programmation orientée objet, un objet null est un objet sans valeur référencée ou qui a un comportement défini comme neutre (null). Le patron de conception de l'objet null décrit l'utilisation de ces objets et de leurs comportements. Il apparaît pour la première fois dans la série de livres Pattern Languages of Program Design[1].
Motivation
Dans la plupart des langages orientés objet comme Java ou C#, les références peuvent être null. Il est nécessaire de vérifier que ces références ne sont pas null avant d'en invoquer les méthodes. En effet, il n'est pas possible d'invoquer une méthode sur une référence null.
Description
À la place d'utiliser une référence null pour communiquer l'absence d'un objet (par exemple un client qui n'existe pas), on utilise un objet qui implémente l'interface attendue mais dont la méthode corps est vide. L'avantage de cette approche par rapport à une implémentation de base est que l'objet null a un comportement vraiment prévisible et n'a pas d'effet secondaire puisqu'il ne fait rien. Par exemple, une fonction peut extraire la liste des fichiers d'un dossier et effectuer une action sur chacun d'entre eux. Dans le cas d'un dossier vide, une réponse possible est de lever une exception ou de retourner une référence null plutôt qu'une liste. Ainsi, le code qui est dans l'attente d'une liste doit vérifier qu'il en a bien reçu une avant de pouvoir continuer. Cela a pour conséquence de compliquer l'architecture du code.
En retournant un objet null (c'est-à-dire une liste vide) à la place, il est inutile de vérifier que la valeur retournée est bien une liste. La fonction appelante peut simplement agir sur la liste de manière normale, c'est-à-dire en ne faisant rien. Cependant, il est toujours possible de vérifier si la valeur retournée est un objet null (c'est-à-dire une liste vide) et réagir différemment si tel en est le souhait.
Le patron de conception de l'objet null peut aussi être utilisé pour agir comme un bouchon dans le cas de tests automatisés si certaines fonctionnalités comme l'appel à une base de données ne sont pas disponibles pour effectuer des tests.
Exemple
Prenons un arbre binaire de nœuds :
class node { node left node right }
Ci-dessous, une manière d'implémenter récursivement le calcul de la taille de l'arbre :
function tree_size(node) { return 1 + tree_size(node.left) + tree_size(node.right) }
Étant donnée que les nœuds enfants peuvent ne pas exister, on doit modifier la structure du code pour vérifier que les valeurs existent et ne sont pas null :
function tree_size(node) { set sum = 1 if node.left exists { sum = sum + tree_size(node.left) } if node.right exists { sum = sum + tree_size(node.right) } return sum }
Cependant, cela rend la structure du code plus compliquée puisqu'on mélange des vérifications techniques et de la logique métier. Le code est alors plus dur à lire. En utilisant, le patron de conception du null object, on peut créer une version spéciale du code qu'on applique seulement pour les nœuds null :
function tree_size(node) { return 1 + tree_size(node.left) + tree_size(node.right) }
function tree_size(null_node) { return 0 }
Cela sépare la logique et le cas particulier dont on traite. Le code est plus facile à comprendre.
Relations avec d'autres patrons de conception
Ce patron peut être considéré comme un cas spécial du patron état et du patron stratégie.
Il ne s'agit pas d'un patron venant du livre Design Patterns, mais il est mentionné dans le livre Refactoring[2] de Martin Fowler et dans Insert Null Object Refactoring de Joshua Kerievsky qui traite de réingénierie logicielle.
Le chapitre 17 de Agile Software Development: Principles, Patterns and Practices de Robert Cecil Martin se consacre à ce patron[3].
Notes et références
- Woolf, Bobby (1998).
- Fowler, Martin, Refactoring. Improving the Design of Existing Code, Addison-Wesley,
- Martin, Robert (2002).
- Portail de la programmation informatique