Commit 195d0f4c authored by sunye's avatar sunye
Browse files

Initial commit

parent 42adf83a
:sectnums:
:toc:
= Distanciel SCE: Création d'une Interface Fluent en Java
= Distanciel SCE: Création d'une Interface Fluide 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.
Plus précisément, nous verrons comment construire 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.
......@@ -163,7 +163,99 @@ interface EmailCreator {
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
== Exercice pratique : Publication de services DNS-SD
Dans cette partie, vous allez appliquer ces notions pour coder une interface fluide.
=== Préparation
. Effectuez une divergence du projet remote où vous vous trouvez actuellement.
Pour rappel, il suffit d’aller utiliser le bouton correspondant en faut de la page d’accueil du projet.
// 1. Créez un nouveau projet *privé* sur le link:gitlab.univ-nantes.fr/[Gitlab de l'université], et appelez le *obligatoirement* `distanciel-idl-jeu-cartes`.
. Effectuez une *divergence* du projet _distanciel_ où vous vous trouvez actuellement.
Pour rappel, il suffit d'aller utiliser le bouton correspondant en faut de la page d'accueil du projet.
. Configurez votre nouveau projet Gitlab obtenu via la divergence de la manière suivante :
** Dans _"Paramètres → Général"_, allez dans _"Visibility, project features, permissions"_, et mettez _"Project visibility"_ à _"Private"_.
Ainsi, vous devenez le seul utilisateur autorisé à accéder à votre code source.
** Dans _"Paramètres → Membres"_, ajoutez comme nouveau membre l’utilisateur virtuel appelé *Naobot*, avec le statut _"Reporter"_.
Cet utilisateur virtuel que nous contrôlons nous donne le droit d’accéder à votre travail et nous permettra de récupérer vos projets.
. Clonez avec `git` votre divergence sur votre ordinateur de travail, ce qui vous donnera un répertoire `remote`
=== Le protocole DNS-SD
DNS _Service Discovery_, ou simplement DNS-SD est un protocole de publication et découverte de services à l'intérieur d'un réseau local, et qui utilise des enregistrements DNS de type SRV, PTR et TXT.
Notre objectif ici n'est pas de comprendre le fonctionnement de ce protocole dans les détails, mais seulement de simplifier la publication de services grâce à une interface fluide.
Plus précisément, nous allons nous intéresser à la création d'instances de la classe `ServiceDescription`, dont la signature du constructeur est donné ci-dessous:
```java
public ServiceDescription(String name, int port, String transport,
String application, String subtype, int weight, int priority, int ttl,
boolean persistent) {
this.name = name;
this.port = port;
this.transport = transport;
this.application = application;
this.subtype = subtype;
this.weight = weight;
this.priority = priority;
this.ttl = ttl;
this.persistent = persistent;
}
```
Comme on peut déduire à partir du constructeur, cette classe possède 8 attributs:
* Seulement 4 sont obligatoires: `name`, `port`, `transport` et `application`.
* La valeur par défaut des attributs `weight` et `priority` est de 0.
* La valeur par défaut de l'attribut `ttl` est de 3.600.
* La valeur par défaut de l'attribut `persistent` est `false`.
* Il est possible qu'un service n'ait pas de sous-type (attribut `subtype` nul).
=== Implémentation
* Première étape: mettre en oeuvre la classe monteur, appelée `SimpleServiceDescriptionBuilder`:
** Cette classe doit contenir exactement les mêmes attributs de la classe `ServiceDescription`.
** Les attributs qui ont une valeur par défaut doivent être initialisés avec cette valeur.
* Deuxième étape: mettre en oeuvre le chaînage d'interfaces:
** Créer une interface par attribut obligatoire, plus une interface de construction: `ServiceNameModifier`,
`ServicePortModifier`, `ServiceTransportModifier`, `ServiceApplicationModifier` et enfin `ServiceDescriptionBuilder`.
** Les 4 premières interfaces doivent spécifier une seule méthode, le modificateur de l'attribut concerné.
Le type de retour de ces modificateurs doit être l'interface suivante.
** Ainsi, le code de l'interface `ServiceNameModifier` doit ressembler à:
+
```java
interface ServiceNameModifier {
ServicePortModifier name(String name);
}
```
** La dernière interface, `ServiceDescriptionBuilder`, doit spécifier la méthode `build()`, dont le type de retour est `ServiceDescription`, ainsi que les modificateurs des attributs optionnels.
* Troisième étape: mettre en oeuvre des interfaces dans la classe `SimpleServiceDescriptionBuilder`:
** Modifier l'en-tête de la classe monteur pour la faire implémenter les 5 interfaces définies ci-dessous.
** Implémenter chacune des méthodes de modification, sans oublier de retourner l'objet courant.
** Implémenter enfin la méthode `build()` qui doit créer une instance de `ServiceDescription`.
* Quatrième et dernière étape: mettre en oeuvre un test unitaire qui utilise votre APU fluide.
** Pensez à vérifier que l'auto-complétion marche correctement.
=== Rendre le projet
Pour rendre le projet, il vous suffit de vous assurer d'avoir :
- bien ajouté *Naobot* comme membre _Reporter_ de votre projet.
- bien validé et publié (commit & push) tous vos fichiers de projet
Tant que tout cela est bien fait avant la date limite de rendu, alors tout est bon !
......
plugins {
id 'java'
id 'maven'
}
group 'fr.unantes'
version '1.0-SNAPSHOT'
sourceCompatibility = 11
repositories {
mavenCentral()
mavenLocal()
}
test {
useJUnitPlatform()
}
dependencies {
compile 'org.atlanmod.commons:commons-core:1.0.4'
testCompile group: 'com.google.truth', name: 'truth', version: '1.0.1'
compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.7'
compile group: 'com.google.code.findbugs', name: 'jsr305', version: '3.0.2'
compile group: 'com.google.guava', name: 'guava', version: '28.2-jre'
testCompile group: 'org.junit.jupiter', name: 'junit-jupiter-params', version: '5.5.2'
testCompile group: 'org.assertj', name: 'assertj-core', version: '3.14.0'
testCompile group: 'org.mockito', name: 'mockito-junit-jupiter', version: '3.3.3'
testCompile group: 'org.springframework', name: 'spring-test', version: '5.2.4.RELEASE'
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.5.2'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.5.2'
}
package fr.unantes.dnssd;
public class ServiceDescription {
private String name;
private int port;
private String transport;
private String application;
private String subtype;
private int weight;
private int priority;
private int ttl;
private boolean persistent;
public ServiceDescription(String name, int port, String transport,
String application, String subtype, int weight, int priority, int ttl,
boolean persistent) {
this.name = name;
this.port = port;
this.transport = transport;
this.application = application;
this.subtype = subtype;
this.weight = weight;
this.priority = priority;
this.ttl = ttl;
this.persistent = persistent;
}
}
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