Dans ce chapitre, démarrons le code de notre application ! Nous allons commencer par implémenter une partie du diagramme UML que nous avons vu ensemble précédemment :
la classe
Product
;la classe
Client
.
Dans un second temps, je vous expliquerai un concept important : la visibilité.
Implémentez un UML
Votre projet
Commençons par créer notre projet dans IntelliJ. Si vous avez oublié comment faire, voici un petit rappel du premier cours. Cette fois, chez moi, le projet se nomme HomeShop et le package com.cursan.homeshop.
Produit
Voici un petit rappel de notre UML :

Commençons par coder cette classe :
package com.cursan.homeshop;
public class Product {
String name;
String description;
double price;
/**
* Display a full description of the product
*/
public void look() {
}
/**
* Add the product to a Bill
* @param bill the concerned bill
* @param quantity the quantity to add
*/
public void buy(Bill bill, Integer quantity) {
}
}
Pour que le code puisse compiler, nous allons créer une classe Bill
vide.
package com.cursan.homeshop;
public class Bill {
}
Un bon réflexe à avoir est de créer immédiatement une classe de tests dès que vous créez une classe. Si les pratiques de TDD vous échappent, je vous invite à consulter ce chapitre du premier cours.
Commencez par créer un dossier test à la racine de votre projet.


Il faut ensuite préciser à IntelliJ que ce dossier va servir à stocker nos tests. Faites clic droit sur le dossier test > Mark Directory As > Test Sources Root.

Maintenant, revenez dans la classe Product
, puis dans le menu Navigate >Test.

IntelliJ ne trouve pas de classe de tests correspondant à Product
, il vous propose de la créer.

Sélectionnez JUnit5.

Voilà ! IntelliJ vient de vous créer une nouvelle classe.

Cette classe contient des erreurs, car, par défaut, notre projet ne contient pas JUnit5. Comme dans le premier cours, résolvez le souci automatiquement via IntelliJ.

Voilà, votre classe de tests est créée. Pour l'instant, Product
ne fait rien, pas besoin d'écrire des tests. Dès que nous voudrons ajouter un comportement, nous rédigerons les tests d'abord dans ProductTest
.
Qu'est-ce que le classpath exactement ?
Le classpath est un paramètre contenant un ensemble de chemins vers des classes Java. Au lancement d'un programme, un outil inclus dans la JVM va scanner ces chemins pour charger toutes les classes nécessaires. Dans notre cas, on ajoute JUnit5.0 dans le classpath pour que cette librairie soit chargée avec notre programme.
Client
On passe maintenant à client. Le code est encore plus simple :
package com.cursan.homeshop;
public class Customer {
String fullname;
String address;
}
La visibilité
Quand on développe du code, il faut toujours penser : "Peut-être qu'un jour, un autre développeur utilisera mon code." C'est pour cette raison que l'on :
nomme correctement nos classes, attributs, méthodes et variables ;
rédige de la javadoc ;
écrit des tests.
Dans cette même logique, la visibilité est une des notions les plus importantes.
Prenons un exemple de la vie réelle :
Quand vous utilisez un four, vous pouvez le démarrer à 180 degrés pendant 10 minutes. Quand vous faites cela, de nombreux mécanismes internes vont être activés (les résistances vont chauffer, la soufflerie va s'activer, etc.).
Vous, en tant qu'utilisateur de ce four, n'avez pas accès à tous ces composants : ils sont cachés par la carcasse du four.
Pour coder un four, nous pourrions faire :
public class Four {
Resistance resistance;
Soufflerie soufflerie;
public void cuire(int temperature, int duree) {
...
}
}
Si nous codons Four
de cette façon, un développeur qui l'utilise pourrait avoir accès à Resistance
et Soufflerie
.
Il pourrait, par exemple, faire :
Four four = new Four();
four.resistance = null;
four.cuire(180, 10);
En supprimant la valeur de resistance
, il risque de casser la logique interne de Four
.
En tant que développeur, vous devez protéger Resistance
et Soufflerie
pour que vous puissiez y avoir accès dans Four
, mais pas à l'extérieur.
Pour cela, il existe un mot clé : private
.
public class Four {
private Resistance resistance;
private Soufflerie soufflerie;
public void cuire(int temperature, int duree) {
...
}
}
En faisant cela, il est impossible de faire fonctionner la ligne four.resistance = null;
. Le compilateur indiquera une erreur. De cette façon, seul le développeur de Four
a un contrôle sur ses composants internes.
Il existe 4 types de visibilités :
private
: uniquement accessible dans la classe ;public
: accessible partout ;""
(rien) : accessible dans le package ;protected
: nous verrons ce type plus tard.
Ce concept est aussi applicable aux méthodes. Continuons avec notre exemple du four. Sur certains fours professionnels, il peut y avoir des fonctions de maintenance accessibles au technicien, mais pas à l'utilisateur final du four. Cela se symboliserait par une méthode accessible uniquement à l'intérieur d'une classe.
public class Four {
...
private void maintenir() {
...
}
}
Les méthodes servent principalement à structurer son code à l'intérieur d'une classe.
Getter et Setter
Par défaut, il faut toujours mettre tous les attributs à private
, afin de bien maîtriser ce que l'on peut faire ou non avec notre classe depuis l'extérieur.
Il faut ensuite se poser la question : est-ce que l'on a besoin de lire cette information depuis l'extérieur ?
Si oui, il faut créer un Getter. C'est une méthode très simple qui ressemble à :
public Resistance getResistance() {
return resistance;
}
Cette fonction retourne une copie de la valeur de resistance
. Les autres développeurs peuvent donc accéder à sa valeur, mais ne peuvent pas la modifier.
La deuxième question à se poser est : est-ce que l'on a besoin de modifier cette information depuis l'extérieur ?
Si oui, il faut créer un Setter. De nouveau le code est très simple :
public void setSoufflerie(Soufflerie soufflerie) {
this.soufflerie = soufflerie;
}
Mais du coup, cela revient au même ? Pas du tout ! Un développeur qui utilise votre classe va voir les méthodes Getter et Setter que vous avez créées. Il sait ce que vous l'autorisez à faire. Un Setter veut clairement dire : "J'ai prévu dans mon code que tu puisses modifier cette valeur."
Implémentez un UML proprement !
Un bon UML précise ce qui est accessible et ce qui ne l'est pas. Il existe 2 types de représentations. Dans la première, très verbeuse, on voit tous les Getter et Setter. Ici, name
, description
et price
ont un Getter. Seul price
possède un Setter.

Le second format est plus concis. Des points verts sur les attributs signalent des Getter. Des points rouges signalent des Setter.

Voici le nouveau code de Product
:
package com.cursan.homeshop;
public class Product {
private String name;
private String description;
private double price;
/**
* Display a full description of the product
*/
public void look() {
System.out.println(String.format(name + " : " + price + "%n" + description));
}
/**
* Add the product to a Bill
*/
public void buy(Bill bill, Integer quantity) {
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
}
Voici l'UML verbeux pour Customer
:

Puis son code :
package com.cursan.homeshop;
public class Customer {
private String fullname;
private String address;
public String getFullname() {
return fullname;
}
public String getAddress() {
return address;
}
}