UKOnline

Convention et bonne pratique

On vient de voir, tout au long de ce chapitre, comment définir ses propres objets en définissant des classes. Afin de rendre les codes qu'on écrit plus lisibles par nous-mêmes et par les autres programmeurs, il est une bonne pratique que de suivre des conventions adoptées par tous. Nous allons maintenant voir, dans cette dernière section de ce chapitre, les conventions les plus connues.

De plus, on peut écrire un même programme de plusieurs manières différentes. Il existe toute une série de règles de bonne pratiques qu'il convient de suivre pour rendre les programmes plus clairs et lisibles par tout le monde. Nous allons également voir quelques règles de bonne pratique, liées à la programmation de manière générale, à Java et à la programmation orientée objets.

Convention de nommage

Le premier lot de règles concerne le choix des différents noms. On a déjà vu comment faire pour choisir un nom aux variables et constantes au premier chapitre. Rappelons brièvement ces règles : par convention, les noms de variables commencent par une minuscule et ne contiennent des majuscules qu'à chaque changement de mot. Pour les constantes, le nom est complètement écrit en majuscules et les mots sont séparés par un tiret de soulignement ( _ ).

Les noms de classes commencent par une majuscule et les noms de méthodes par une minuscule. Le nom de ces deux éléments suivent également la casse chameau, c'est-à-dire qu'on utilise une majuscule à chaque changement de mot. Un nom de classe suivant cette convention pourrait être HybridCar et un exemple de nom de méthode serait startEngine.

De plus, pour les noms de classe, on va habituellement utiliser des noms communs qui décrivent un concept, tandis que pour les noms de méthode, on utilise une combinaison verbe+nom qui décrit ce que fait la méthode. Les noms de ces éléments doivent être le plus concis et descriptif possible.

Ces conventions sont surtout importantes pour tous les éléments publics de votre programme puisqu'ils sont visibles partout et ce sont précisément ceux-ci qui sont susceptibles d'être utilisés par d'autres programmeurs. Utiliser des noms parlants, c'est faire de l'auto-documentation. En effet, si le nom d'une méthode explique déjà ce qu'elle fait, il ne faudra plus ajouter un commentaire supplémentaire.

Convention de nommage JavaBeans

Une autre convention concerne les noms de méthodes, la convention de nommage JavaBeans pour les méthodes directement liées à l'accès (getter) ou la mise à jour (setter) des attributs d'une classe. Le nom des premières doit commencer par get suivi du nom de l'attribut qui est récupéré et le nom des secondes doit commencer par set suivi du nom de l'attribut qui est modifié. Pour les méthodes qui récupère la valeur d'un attribut booléen, leurs noms commencera plutôt par is. Ces méthodes doivent être déclarées public. Les getters renvoient une valeur et ne prennent aucun paramètre et les setters doivent être void et prennent un seul paramètre. Voici quelques exemples :

Instruction return

La règle suivante s'applique aux méthodes qui renvoient une valeur, en particulier à celles qui renvoie un booléen. Ce que les débutants font souvent avec une méthode qui doit renvoyer un booléen est d'utiliser une instructionif-else pour gérer les deux cas, comme vous le montre l'exemple suivant :

La méthode précédente est tout à fait correcte, elle compile et fait exactement ce qu'il faut. Néanmoins, il y a beaucoup trop de code pour rien, et le corps de la méthode structuré ainsi n'est pas très parlant. On teste donc la valeur de l'expression booléenne size == 0. Si sa valeur est true, on renvoie true et sinon, c'est que sa valeur vaut false, et on renvoie false. Vous aurez tout de suite compris le changement à faire, il suffit de directement renvoyer la valeur de l'expression size == 0 puisque c'est ce qu'on veut faire.

La méthode est beaucoup plus courte, plus lisible et traduit maintenant exactement ce qu'on voulait faire.

Nombre d'instructions return

Un autre souci qui existe concerne le nombre d'instructions return à utiliser dans une méthode. Il y a deux grand camps : ceux qui insistent sur le fait qu'il ne faut qu'une seule instruction return par méthode, se trouvant à la fin de son corps; et il y a les autres pour qui ce n'est pas si important. Il n'y a pas vraiment l'un ou l'autre camp qui est le meilleur, chacun des deux camps à de bons arguments.

Prenons par exemple une méthode qui teste si un nombre entier est premier (seulement divisible par 1 et par lui-même). On va tester tous les entiers compris entre 2 et $n - 1$ et si on en trouve un qui divise $n$, c'est que $n$ n'est pas premier et on renvoie false. Si on arrive au bout de la boucle, c'est que $n$ n'est divisible que par 1 et par lui-même et est donc premier et on renvoie true. Voici le code le plus naturel que l'on puisse écrire pour cette méthode :

On se retrouve donc avec une boucle for qui peut être arrêtée de deux façons différentes : soit la condition de la boucle finit par être fausse, soit l'instruction return false; est atteinte. Rappelez-vous, l'instruction return quitte la méthode dans laquelle elle se trouve. Pour n'avoir qu'une seule instruction return, il faut ajouter une variable booléenne et modifier la condition de la boucle for :

Cette fois-ci, on initialise une variable booléenne prime à true. On fait donc la supposition que le nombre $n$ est premier. Ensuite, on effectue la boucle de 2 à $n - 1$ tant que prime vaut true. Dans le corps de la boucle, si on se rend compte que $n$ n'est pas premier, on change la valeur de la variable prime en la passant à false, ce qui aura pour effet d'arrêter la boucle. Pour finir, la méthode renvoie prime.

Instruction else inutile

Rappelez-vous que l'instruction return quitte la méthode dans laquelle vous êtes. Dès lors, lorsqu'on écrit une méthode qui renvoie une valeur, on peut assez souvent se passer de l'instruction else, afin d'éviter une augmentation du niveau d'indentation du code lorsqu'on enchaine les instructions if-else. Voyons un exemple d'une méthode qui renvoie une chaine de caractères selon la valeur d'une note comprise entre 0 et 20 :

Si la condition du if est satisfaite, la première instruction return est atteinte et l'exécution de la méthode est terminée. Ce qui suit l'instruction if ne sera donc pas exécuté. Par contre, si la condition n'est pas satisfaite, l'exécution continue avec l'instruction else. On peut simplifier le code et écrire :

Pourquoi on peut se passer de l'instruction else ? Car le code qui suit l'instruction if ne sera pas exécuté si sa condition est satisfaite. On a donc un else implicite. C'est une bonne pratique permettant d'alléger le code source et diminuer le niveau de sa plus grande indentation.

Méthode privée

Enfin, terminons avec l'utilisation de méthodes privées. Celles-ci ne seront accessibles que depuis la classe dans laquelle elles sont définies. On les utilise pour simplifier le code et le rendre plus lisible. Revenons par exemple à la classe Rectangle qu'on a définie précédemment. On y avait ajouté deux méthodes contains pour savoir si un point et si un rectangle se trouve à l'intérieur du rectangle représente par l'objet cible.

Ces deux méthodes ont comme point commun de tester si une valeur est comprise entre deux autres. On pourrait donc les simplifier en définissant une méthode privée isBetween qui permet de réaliser ce test.

Voici donc cette méthode et les méthodes contains réécrites :

La méthode isBetween n'a pas à être visible de l'extérieur, car elle est uniquement utilisée pour simplifier l'implémentation des méthodes contains; cela justifie donc sa visibilité privée. Elle ne fait pas partie de l'interface de la classe Rectangle.