Commit 42adf83a authored by sunye's avatar sunye
Browse files

README - Initial explanations

parent b75e90a4
:sectnums:
:toc:
= Distanciel SCE: Création d'une Interface Fluent en Java
Pour cette partie en distanciel du cours de Construction et Évolution de Logiciels, nous allons nous intéresser à la création d'APIs lisibles et faciles à utiliser.
Plus précisément, nous verrons comment cronstruire une _Fluent Interface_ (en français, désignation chaînée ou chaînage de méthodes) et comment se servir de l'auto-complétion des environnements de développement pour utiliser ces interfaces.
WARNING: Cette partie du cours n'est *pas optionnelle* !
Pour l'examen, vous devez comprendre les principes présentés ici et être capables de refaire les exercices.
- La _première partie_ de ce distanciel est un introduction aux Interfaces Fluent.
- La _seconde partie_ de ce distanciel est un *travail pratique*, où vous créerez une Interface Fluent en Java.
== Le Pattern Fluent Builder
En construction de logiciels, le pattern _Fluent Builder_ (en français, monteur fluide)
est particulièrement utile lorsque l'on souhaite construire des objets complexes.
Par exemple, supposons que l'on souhaite construire un objet complexe en créant une instance de son _builder_ (monteur),
en appelant les _setters_ (modificateurs) respectifs, et enfin, en appelant la méthode de construction.
Une fois la méthode de construction exécutée, vous récupérerez l'objet de la classe souhaitée.
```java
EmailMessageBuilder builder = new EmailMessageBuilder();
EmailMessage message = builder.buildEmailMessage();
message.setFrom("gerson.sunye@univ-nantes.fr");
message.seTo("licence.informatique@univ-nantes.fr");
message.setSubject("Distanciel");
message.setBody("Au travail !!!");
message.send();
```
Ce code semble très simple, mais il y a une difficulté potentielle:
si la construction de l'objet est complexe et qu'il y a trop d'attributs à modifier,
le développeur peut en oublier certains et créer un objet incomplet.
Dans de nombreuses applications, il y a souvent une entité centrale, comme une "Commande", un "Produit" ou un "Service",
dont les instances sont créées dans différentes morceaux de code.
Dans ces cas, l'oubli d`initialiser un attribut peut s'avérer très couteux en termes de déboggage et de maintenance.
Une question se pose:
[quote]
.Question:
Comment aider le développeur à se rappeler de tous les attributs, obligatoires et optionnels?
La réponse est de forcer le développeur à initialiser tous les attributs obligatoires *avant* d'appeler la méthode de construction.
Ainsi, tous les attributs obligatoires seront initialisés et l'objet créé sera complet.
[IMPORTANT]
Comment forcer le développeur à initialiser correctement un objet?::
En utilisant le patron _Fluent Builder_.
L'idée c'est qu'au lieu de précéder chaque appel de méthode par le nom de l'objet, ce qui conduit à un style verbeux, le nom de l'objet reste actif dans toute l'instruction en cours.
Le code devient ainsi à la fois plus concis et plus clair.
Par exemple:
```java
EmailMessage message = EmailMessageBuilder.builder()
.from("gerson.sunye@univ-nantes.fr")
.to("licence.informatique@univ-nantes.fr")
.subject("Distanciel")
.body("Au travail !!!")
.build();
```
La réduction de verbosité est semblable à celle de l'expression `with` en Pascal, bien que sur des principes différents.
=== Chainage de méthodes
Ce style (ou idiome) de programmation, appelé _chainage de méthodes_ a été introduit par le langage Smalltalk, où par convention les modificateurs retournent l'objet modifié (`this`).
Dans le cas de Java, la logique est semblable: toutes les méthodes de configuration (`from`, `to`, etc.) seront spécifiées dans la `Builder` et retourneront une instance de cette classe.
Par exemple, la méthode `from()` sera mise en oeuvre comme suit:
```java
public EmailMessageBuilder from(String sender) {
this.from = sender;
return this;
}
```
Quant à la méthode `to()`, sa mise en oeuvre sera semblable:
```java
public EmailMessageBuilder to(String recipient) {
this.to = recipient;
return this;
}
```
Si le chaînage de méthodes permet de simplifier le code de création d'objets,
il ne peut pas empêcher l'oubli de certains attributs, ni l'appel de la méthode `build()` avant que tous les attributs soient initialisés.
Une nouvelle question se pose alors:
[quote]
.Question:
Comment empêcher le développeur d'appeler la méthode de construction avant d'initialiser tous les attributs obligatoires ?
Pour répondre à cette question, nous allons utiliser le chaînage d'interfaces.
=== Le chaînage d'interfaces
La logique du chaînage d'interfaces est de limiter l'accès lors du chaînage de méthodes, en créant une interface pour chaque attribut obligatoire et
en modifiant le type de retour de chaque modificateur pour le faire retourner la prochaine interface.
Compliqué ? Oui, en effet, mais la logique deviendra plus claire en regardant le code des interfaces:
```java
interface EmailFrom {
EmailTo from(String sender);
}
interface EmailTo {
EmailSubject to(String recipient);
}
interface EmailSubject {
EmailBody subject(String subject);
}
interface EmailBody {
EmailCreator body(String contents);
}
interface EmailCreator {
EmailMessage build();
}
```
Ainsi, pour atteindre l'interface `EmailCreator`, on doit passer par une suite d'interfaces, ce qui oblige le développeur à appeler différentes méthodes avant de pouvoir accéder à la méthode `build()`.
La question qu'on peut se poser maintenant est : "- Faut-il implémenter toutes ces interfaces par une nouvelle classe ?".
La réponse est simple, non, car en Java, rappelez-vous, une classe peut implémenter plus d'une interface.
C'est à la classe builder de le faire:
```java
public class EmailMessageBuilder
implements EmailFrom, EmailTo, EmailSubject, EmailBody, EmailBody {
}
```
Ainsi, le développeur manipule toujours le même objet, mais n'a pas toujours accès aux mêmes méthodes.
Une autre question que l'on peut se poser est : "- Comment faire lorsque certains attributs sont optionnels ?".
En effet, dans notre exemple on peut penser à ajouter ces attributs optionnels, comme le champ "CC" d'un message.
Dans ce cas, on ajoute les modificateurs de ces attributs à la dernière interface, celle qui contient la méthode `build()`:
```java
interface EmailCreator {
EmailCreator cc(String recipient);
EmailMessage build();
}
```
En prime, l'auto-complétion de l'IDE guidera les développeurs à travers les interfaces, en proposant par exemple, la méthode `to()`, après la méthode `from()` ou la méthode `build()` après la méthode `body()`.
== Exercice
== Liens utiles
- https://dzone.com/articles/fluent-builder-pattern
- https://dzone.com/articles/making-java-fluent-api-more-flexible
- https://github.com/guilhermechapiewski/fluent-mail-api
\ No newline at end of file
# Distance Learning
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment