translation: Added french documentation for several patterns (#2617)

* translate Abstract Document documentation in french

* translate Abstract Document documentation in french for issue #2278

* french translation of abstract factory

* French translation for active-object

* translate Abstract Document documentation in french

* translate Abstract Document documentation in french for issue #2278

* french translation of abstract factory

* French translation for active-object

* tranlate to french: acyclic-visitore, adapter, aggregator-microservice, ambassador, api-gateway, arrange-act-assert, async-method-invocation, balking, bridge.
This commit is contained in:
believe
2024-01-27 11:20:32 +00:00
committed by GitHub
parent 4a315e7f4b
commit 87a774c9d6
12 changed files with 1981 additions and 0 deletions
+199
View File
@@ -0,0 +1,199 @@
---
title: Abstract Document
category: Structural
language: fr
tag:
- Extensibility
---
## Intention
Le patron de conception "Abstract Document" est un modèle de conception structurelle qui vise à fournir un moyen
cohérent de gérer les structures de données hiérarchiques et arborescentes en définissant une interface commune pour
différents types de documents.
## Explication
Le patron de conception "Abstract Document" permet de gérer des propriétés supplémentaires non statiques. Ce modèle
utilise le concept de traits pour assurer la sécurité des types et séparer les propriétés des différentes
classes dans un ensemble d'interfaces
Exemple concret
> Prenons l'exemple d'une voiture composée de plusieurs pièces. Cependant, nous ne savons pas si la voiture en question possède réellement toutes les pièces ou seulement certaines d'entre elles. Nos voitures sont dynamiques et extrêmement flexibles.
En clair
> Le modèle de document abstrait permet d'attacher des propriétés à des objets indépendament de ces derniers.
Wikipedia dit
> Un patron de conception structurelle orienté objet pour organiser des objets comme clé-valeur faiblement typés et exposer des données à l'aide de vues typées. L'objectif de ce modèle est d'atteindre un haut degré de flexibilité entre les composants
dans un langage fortement typé où de nouvelles propriétés peuvent être ajoutées à l'arbre d'objets à la volée, sans perdre le soutien de la sécurité de type.
**Exemple de programme**
Définissons en premier les classes de base `Document` et `AbstractDocument`. Ils font en sorte que l'objet contienne une carte(map) de propriétés et un nombre quelconque d'objets enfants.
```java
public interface Document {
Void put(String key, Object value);
Object get(String key);
<T> Stream<T> children(String key, Function<Map<String, Object>, T> constructor);
}
public abstract class AbstractDocument implements Document {
private final Map<String, Object> properties;
protected AbstractDocument(Map<String, Object> properties) {
Objects.requireNonNull(properties, "properties map is required");
this.properties = properties;
}
@Override
public Void put(String key, Object value) {
properties.put(key, value);
return null;
}
@Override
public Object get(String key) {
return properties.get(key);
}
@Override
public <T> Stream<T> children(String key, Function<Map<String, Object>, T> constructor) {
return Stream.ofNullable(get(key))
.filter(Objects::nonNull)
.map(el -> (List<Map<String, Object>>) el)
.findAny()
.stream()
.flatMap(Collection::stream)
.map(constructor);
}
...
}
```
Ensuite, nous définissons une enumération `Property` et un ensemble d'interfaces pour le type, le prix, le modèle et les pièces. Cela nous permet de créer une interface statique pour notre classe `Car`.
```java
public enum Property {
PARTS, TYPE, PRICE, MODEL
}
public interface HasType extends Document {
default Optional<String> getType() {
return Optional.ofNullable((String) get(Property.TYPE.toString()));
}
}
public interface HasPrice extends Document {
default Optional<Number> getPrice() {
return Optional.ofNullable((Number) get(Property.PRICE.toString()));
}
}
public interface HasModel extends Document {
default Optional<String> getModel() {
return Optional.ofNullable((String) get(Property.MODEL.toString()));
}
}
public interface HasParts extends Document {
default Stream<Part> getParts() {
return children(Property.PARTS.toString(), Part::new);
}
}
```
Nous sommes maintenant prêts à présenter la classe `Car`.
```java
public class Car extends AbstractDocument implements HasModel, HasPrice, HasParts {
public Car(Map<String, Object> properties) {
super(properties);
}
}
```
Enfin, voici comment nous construisons et utilisons la "voiture" dans un exemple complet.
```java
LOGGER.info("Constructing parts and car");
var wheelProperties = Map.of(
Property.TYPE.toString(), "wheel",
Property.MODEL.toString(), "15C",
Property.PRICE.toString(), 100L);
var doorProperties = Map.of(
Property.TYPE.toString(), "door",
Property.MODEL.toString(), "Lambo",
Property.PRICE.toString(), 300L);
var carProperties = Map.of(
Property.MODEL.toString(), "300SL",
Property.PRICE.toString(), 10000L,
Property.PARTS.toString(), List.of(wheelProperties, doorProperties));
var car = new Car(carProperties);
LOGGER.info("Here is our car:");
LOGGER.info("-> model: {}", car.getModel().orElseThrow());
LOGGER.info("-> price: {}", car.getPrice().orElseThrow());
LOGGER.info("-> parts: ");
car.getParts().forEach(p -> LOGGER.info("\t{}/{}/{}",
p.getType().orElse(null),
p.getModel().orElse(null),
p.getPrice().orElse(null))
);
// Constructing parts and car
// Here is our car:
// model: 300SL
// price: 10000
// parts:
// wheel/15C/100
// door/Lambo/300
```
## Diagramme de classes
![alt text](../../../abstract-document/etc/abstract-document.png "Abstract Document Traits and Domain")
## Application
Ce modèle est particulièrement utile dans les scénarios où vous avez différents types de documents qui partagent des attributs ou des comportements communs, mais qui ont également des attributs ou des comportements uniques, spécifiques à leurs types individuels. Voici quelques
Voici quelques scénarios dans lesquels le patron de conception Abstract Document peut s'appliquer :
* Systèmes de gestion de contenu (SGC) : dans un SGC (CMS en anglais), vous pouvez avoir différents types de contenu tels que des articles, des images, des vidéos, etc. Chaque type de contenu peut avoir des attributs communs tels que la date de création, l'auteur et les balises, mais aussi des attributs spécifiques tels que les dimensions de l'image pour les images ou la durée de la vidéo pour les vidéos.
* Systèmes de gestion de fichiers : Si vous concevez un système de gestion de fichiers dans lequel différents types de fichiers doivent être gérés; tels que des documents, des images, des fichiers audio et des répertoires, le patron "Abstract Document" peut vous aider à fournir un moyen cohérent d'accéder à des attributs tels que la taille du fichier, la date de création, etc., tout en autorisant des attributs spécifiques tels que la résolution de l'image ou la durée de l'audio.
* Systèmes de commerce électronique ou vente en ligne : Une plateforme de commerce électronique peut avoir différents types de produits tels que des produits physiques, des téléchargements numériques et des abonnements. Chaque type peut partager des attributs communs tels que le nom, le prix et la description, tout en ayant des attributs uniques tels que le poids d'expédition pour les produits physiques ou le lien de téléchargement pour les produits numériques.
* Systèmes de dossiers médicaux : En médécine, les dossiers des patients peuvent inclure différents types de données telles que des données démographiques, des antécédents médicaux, des résultats d'examens et des prescriptions. Le patron de conception "abstract document" peut aider à gérer des attributs partagés tels que l'ID du patient et sa date de naissance, tout en s'adaptant à des attributs spécialisés tels que les résultats d'examens ou les médicaments prescrits.
* Gestion de la configuration : Lorsqu'il s'agit de paramètres de configuration pour des applications logicielles, il peut y avoir différents types d'éléments de configuration, chacun avec son propre ensemble d'attributs. Le patron de conception "abstract document" peut être utilisé pour gérer ces éléments de configuration tout en garantissant une manière cohérente d'accéder à leurs attributs et de les manipuler.
* Plateformes éducatives : Les systèmes éducatifs peuvent disposer de différents types de matériel pédagogique, tels que des contenus textuels, des vidéos, des quiz et des devoirs. Les attributs communs tels que le titre, l'auteur et la date de publication peuvent être partagés, tandis que les attributs uniques tels que la durée des vidéos ou les dates d'échéance des devoirs peuvent être spécifiques à chaque type.
* Outils de gestion de projet : Dans les applications de gestion de projet, vous pouvez avoir différents types de tâches comme les tâches à faire, les étapes et les problèmes. Le modèle de document abstrait peut être utilisé pour gérer des attributs généraux tels que le nom de la tâche et le destinataire, tout en autorisant des attributs spécifiques tels que la date du jalon ou la priorité du problème.
L'idée principale du patron de conception Abstract Document est de fournir un moyen flexible et extensible de gérer différents types de documents ou d'entités avec des attributs partagés et distincts. En définissant une interface commune et en l'implémentant
dans les différents types de documents, vous pouvez obtenir une approche plus organisée et cohérente de la manipulation de structures de données complexes.
## Crédits
* [Wikipedia: Abstract Document Pattern](https://en.wikipedia.org/wiki/Abstract_Document_Pattern)
* [Martin Fowler: Dealing with properties](http://martinfowler.com/apsupp/properties.pdf)
* [Pattern-Oriented Software Architecture Volume 4: A Pattern Language for Distributed Computing (v. 4)](https://www.amazon.com/gp/product/0470059028/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0470059028&linkId=e3aacaea7017258acf184f9f3283b492)
+227
View File
@@ -0,0 +1,227 @@
---
title: Abstract Factory
category: Creational
language: fr
tag:
- Gang of Four
---
## Également connu sous le nom de
Kit
## Intention
Fournir une interface permettant de créer des familles d'objets liés ou dépendants
sans spécifier leurs classes concrètes.
## Explication
Exemple concret
> Pour créer un royaume, nous avons besoin d'objets ayant un thème commun. Le royaume elfique a besoin d'un roi elfique, d'un château elfique et d'une armée elfique, tandis que le royaume orque a besoin d'un roi orque, d'un château orque et d'une armée orque. Il existe une dépendance entre les objets du royaume.
En clair
> Une usine d'usines ; une usine qui regroupe les usines individuelles mais liées/dépendantes sans spécifier leurs classes concrètes.
Wikipedia dit
> Le modèle d'usine abstraite permet d'encapsuler un groupe d'usines individuelles ayant un thème commun sans spécifier leurs classes concrètes.
**Exemple de programme**
Traduction de l'exemple du royaume ci-dessus. Tout d'abord, nous avons quelques interfaces et implémentations pour les objets du royaume.
```java
public interface Castle {
String getDescription();
}
public interface King {
String getDescription();
}
public interface Army {
String getDescription();
}
// Elven implementations ->
public class ElfCastle implements Castle {
static final String DESCRIPTION = "This is the elven castle!";
@Override
public String getDescription() {
return DESCRIPTION;
}
}
public class ElfKing implements King {
static final String DESCRIPTION = "This is the elven king!";
@Override
public String getDescription() {
return DESCRIPTION;
}
}
public class ElfArmy implements Army {
static final String DESCRIPTION = "This is the elven Army!";
@Override
public String getDescription() {
return DESCRIPTION;
}
}
// Orcish implementations similarly -> ...
```
Ensuite, nous avons l'abstraction et les implémentations de la fabrique de royaume.
```java
public interface KingdomFactory {
Castle createCastle();
King createKing();
Army createArmy();
}
public class ElfKingdomFactory implements KingdomFactory {
@Override
public Castle createCastle() {
return new ElfCastle();
}
@Override
public King createKing() {
return new ElfKing();
}
@Override
public Army createArmy() {
return new ElfArmy();
}
}
public class OrcKingdomFactory implements KingdomFactory {
@Override
public Castle createCastle() {
return new OrcCastle();
}
@Override
public King createKing() {
return new OrcKing();
}
@Override
public Army createArmy() {
return new OrcArmy();
}
}
```
Nous disposons maintenant d'une fabrique abstraite qui nous permet de créer une famille d'objets apparentés, par exemple la fabrique de royaume elfique crée un château elfique, un roi et une armée, etc.
```java
var factory = new ElfKingdomFactory();
var castle = factory.createCastle();
var king = factory.createKing();
var army = factory.createArmy();
castle.getDescription();
king.getDescription();
army.getDescription();
```
Sortie du programme :
```java
This is the elven castle!
This is the elven king!
This is the elven Army!
```
Maintenant, nous pouvons concevoir une fabrique pour nos différentes fabriques de royaumes. Dans cet exemple, nous avons créé `FactoryMaker`, responsable de retourner une instance de `ElfKingdomFactory` ou de `OrcKingdomFactory`.
Le client peut utiliser `FactoryMaker` pour créer la fabrique concrète désirée qui, à son tour, produira différents objets concrets (dérivés de `Army`, `King`, `Castle`).
Dans cet exemple, nous avons également utilisé une énumération pour paramétrer le type de fabrique de royaume que le client va demander.
```java
public static class FactoryMaker {
public enum KingdomType {
ELF, ORC
}
public static KingdomFactory makeFactory(KingdomType type) {
return switch (type) {
case ELF -> new ElfKingdomFactory();
case ORC -> new OrcKingdomFactory();
default -> throw new IllegalArgumentException("KingdomType not supported.");
};
}
}
public static void main(String[] args) {
var app = new App();
LOGGER.info("Elf Kingdom");
app.createKingdom(FactoryMaker.makeFactory(KingdomType.ELF));
LOGGER.info(app.getArmy().getDescription());
LOGGER.info(app.getCastle().getDescription());
LOGGER.info(app.getKing().getDescription());
LOGGER.info("Orc Kingdom");
app.createKingdom(FactoryMaker.makeFactory(KingdomType.ORC));
--similar use of the orc factory
}
```
## Diagramme de classes
![alt text](../../../abstract-factory/etc/abstract-factory.urm.png "Abstract Factory class diagram")
## Application
Utiliser le patron de conception "abstract factory" lorsque
* Le système doit être indépendant de la manière dont ses produits sont créés, composés et représentés.
* Le système doit être configuré avec l'une des multiples familles de produits.
* La famille d'objets produits apparentés est conçue pour être utilisée ensemble, et vous devez faire respecter cette contrainte
* Vous voulez fournir une bibliothèque de classes de produits, et vous voulez révéler seulement leurs interfaces, pas leurs implémentations.
* La durée de vie de la dépendance est conceptuellement plus courte que la durée de vie du consommateur.
* Vous avez besoin d'une valeur d'exécution pour construire une dépendance particulière.
* Vous voulez décider quel produit appeler à partir d'une famille au moment de l'exécution.
* Vous devez fournir un ou plusieurs paramètres qui ne sont connus qu'au moment de l'exécution avant de pouvoir résoudre une dépendance.
* Lorsque vous avez besoin d'une cohérence entre les produits.
* Vous ne voulez pas modifier le code existant lorsque vous ajoutez de nouveaux produits ou de nouvelles familles de produits au programme.
Exemples de cas d'utilisation
* Choisir d'appeler l'implémentation appropriée de FileSystemAcmeService ou DatabaseAcmeService ou NetworkAcmeService au moment de l'exécution.
* L'écriture de cas de tests unitaires devient beaucoup plus facile.
* Outils d'interface utilisateur pour différents systèmes d'exploitation.
## Conséquences
* L'injection de dépendances en Java masque les dépendances des classes de service qui peuvent entraîner des erreurs d'exécution qui auraient été détectées au moment de la compilation.
* Si le modèle est idéal pour la création d'objets prédéfinis, l'ajout de nouveaux objets peut s'avérer difficile.
* Le code devient plus compliqué qu'il ne devrait l'être car un grand nombre de nouvelles interfaces et classes sont introduites en même temps que le modèle.
## Tutoriels
* [Abstract Factory Pattern Tutorial](https://www.journaldev.com/1418/abstract-factory-design-pattern-in-java)
## Utilisations connues
* [javax.xml.parsers.DocumentBuilderFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/parsers/DocumentBuilderFactory.html)
* [javax.xml.transform.TransformerFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/transform/TransformerFactory.html#newInstance--)
* [javax.xml.xpath.XPathFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/xpath/XPathFactory.html#newInstance--)
## Modèles apparentés ou similaire (de la même catégorie)
* [Factory Method](https://java-design-patterns.com/patterns/factory-method/)
* [Factory Kit](https://java-design-patterns.com/patterns/factory-kit/)
## Crédits
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)
* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b)
+128
View File
@@ -0,0 +1,128 @@
---
title: Active Object
category: Concurrency
language: fr
tag:
- Performance
---
## Intention
Le patron de conception des "active object" actifs dissocie l'exécution et l'invocation des méthodes pour les objets qui résident chacun dans leur fil de contrôle. L'objectif est d'introduire la concurrence en utilisant l'invocation asynchrone des méthodes et un planificateur pour traiter les demandes.
## Explication
La classe qui met en œuvre le patron "active object", contiendra un mécanisme d'auto-synchronisation sans utiliser de méthodes "synchronisées".
**Exemple concret**
> Les orques sont connus pour leur caractère sauvage et leur âme indomptable. Il semble qu'ils aient leur propre système de contrôle basé sur leur comportement antérieur.
Pour mettre en œuvre une créature qui possède son propre mécanisme de contrôle et qui n'expose que son API et non l'exécution elle-même, nous pouvons utiliser le patron "active-object".
**Exemple de programme**
```java
public abstract class ActiveCreature{
private final Logger logger = LoggerFactory.getLogger(ActiveCreature.class.getName());
private BlockingQueue<Runnable> requests;
private String name;
private Thread thread;
public ActiveCreature(String name) {
this.name = name;
this.requests = new LinkedBlockingQueue<Runnable>();
thread = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
requests.take().run();
} catch (InterruptedException e) {
logger.error(e.getMessage());
}
}
}
}
);
thread.start();
}
public void eat() throws InterruptedException {
requests.put(new Runnable() {
@Override
public void run() {
logger.info("{} is eating!",name());
logger.info("{} has finished eating!",name());
}
}
);
}
public void roam() throws InterruptedException {
requests.put(new Runnable() {
@Override
public void run() {
logger.info("{} has started to roam the wastelands.",name());
}
}
);
}
public String name() {
return this.name;
}
}
```
Nous pouvons constater que toute classe qui hérite de la classe ActiveCreature aura son propre fil de contrôle pour invoquer et exécuter les méthodes.
Par exemple, la classe Orc :
```java
public class Orc extends ActiveCreature {
public Orc(String name) {
super(name);
}
}
```
Désormais, nous pouvons créer plusieurs créatures telles que des orques, leur dire de manger et d'errer, et elles s'exécuteront selon leur propre fil(mechanisme) de contrôle :
```java
public static void main(String[] args) {
var app = new App();
app.run();
}
@Override
public void run() {
ActiveCreature creature;
try {
for (int i = 0;i < creatures;i++) {
creature = new Orc(Orc.class.getSimpleName().toString() + i);
creature.eat();
creature.roam();
}
Thread.sleep(1000);
} catch (InterruptedException e) {
logger.error(e.getMessage());
}
Runtime.getRuntime().exit(1);
}
```
## Diagramme de classe
![alt text](../../../active-object/etc/active-object.urm.png "Active Object class diagram")
## Tutoriels
* [Android and Java Concurrency: The Active Object Pattern](https://www.youtube.com/watch?v=Cd8t2u5Qmvc)
+162
View File
@@ -0,0 +1,162 @@
---
title: Acyclic Visitor
category: Behavioral
language: fr
tag:
- Extensibility
---
## Intention
Permettre l'ajout de nouvelles fonctions à des hiérarchies de classes existantes sans affecter ces hiérarchies et sans
créer de cycles de dépendance gênants inhérents au pqtron de conception GoF visitor.
## Explication
Exemple concret
> Nous disposons d'une hiérarchie de classes de modems. Les modems de cette hiérarchie doivent être visités
> par un algorithme externe basé sur des critères de filtrage (s'agit-il d'un modem compatible Unix ou DOS).
En clair
> Le visiteur acyclique permet d'ajouter des fonctions à des hiérarchies de classes existantes sans modifier ces dernières.
[WikiWikiWeb](https://wiki.c2.com/?AcyclicVisitor) dit
> Le modèle du visiteur acyclique permet d'ajouter de nouvelles fonctions aux hiérarchies de classes existantes
> sans affecter ces hiérarchies et sans créer les cycles de dépendance inhérents au patron de conception GangOfFour visitor.
**Exemple de Programme**
Ci-dessous la hierarchie `Modem`.
```java
public abstract class Modem {
public abstract void accept(ModemVisitor modemVisitor);
}
public class Zoom extends Modem {
...
@Override
public void accept(ModemVisitor modemVisitor) {
if (modemVisitor instanceof ZoomVisitor) {
((ZoomVisitor) modemVisitor).visit(this);
} else {
LOGGER.info("Only ZoomVisitor is allowed to visit Zoom modem");
}
}
}
public class Hayes extends Modem {
...
@Override
public void accept(ModemVisitor modemVisitor) {
if (modemVisitor instanceof HayesVisitor) {
((HayesVisitor) modemVisitor).visit(this);
} else {
LOGGER.info("Only HayesVisitor is allowed to visit Hayes modem");
}
}
}
```
Ensuite, nous introduisons la hiérarchie `ModemVisitor`.
```java
public interface ModemVisitor {
}
public interface HayesVisitor extends ModemVisitor {
void visit(Hayes hayes);
}
public interface ZoomVisitor extends ModemVisitor {
void visit(Zoom zoom);
}
public interface AllModemVisitor extends ZoomVisitor, HayesVisitor {
}
public class ConfigureForDosVisitor implements AllModemVisitor {
...
@Override
public void visit(Hayes hayes) {
LOGGER.info(hayes + " used with Dos configurator.");
}
@Override
public void visit(Zoom zoom) {
LOGGER.info(zoom + " used with Dos configurator.");
}
}
public class ConfigureForUnixVisitor implements ZoomVisitor {
...
@Override
public void visit(Zoom zoom) {
LOGGER.info(zoom + " used with Unix configurator.");
}
}
```
Enfin, voici les visitors en action.
```java
var conUnix = new ConfigureForUnixVisitor();
var conDos = new ConfigureForDosVisitor();
var zoom = new Zoom();
var hayes = new Hayes();
hayes.accept(conDos);
zoom.accept(conDos);
hayes.accept(conUnix);
zoom.accept(conUnix);
```
Sortie du programme :
```
// Hayes modem used with Dos configurator.
// Zoom modem used with Dos configurator.
// Only HayesVisitor is allowed to visit Hayes modem
// Zoom modem used with Unix configurator.
```
## Diagramme de classes
![alt text](../../../acyclic-visitor/etc/acyclic-visitor.png "Acyclic Visitor")
## Application
Ce patron de conception peut être utilisé:
* Pour ajouter ne nouvelle fonction à une hiérarchie existante sans avoir à modifier ou à affecter cette hiérarchie.
* Lorsqu'il existe des fonctions qui opèrent sur une hiérarchie, mais qui n'appartiennent pas à la hiérarchie elle-même. Par exemple, le problème ConfigureForDOS / ConfigureForUnix / ConfigureForX.
* Lorsque vous devez éffectuer des opérations très différentes sur un objet en fonction de son type.
* Lorsque la hiérarchie des classes visitées sera fréquemment étendue avec de nouveaux dérivés de la classe Element.
*Lorsque la recompilation, l'interconnexion, le réessai ou la redistribution des dérivés de Element sont très coûteux.
## Tutoriel
* [Acyclic Visitor Pattern Example](https://codecrafter.blogspot.com/2012/12/the-acyclic-visitor-pattern.html)
## Consequences
Le bon côté:
* Pas de cycles de dépendance entre les hiérarchies de classes.
* Il n'est pas nécessaire de recompiler tous les visiteurs si un nouveau visiteur est ajouté.
* Ne provoque pas d'échec de compilation chez les visiteurs existants si la hiérarchie des classes a un nouveau membre.
Le mauvais :
* viole le [principe de substitution de Liskov](https://java-design-patterns.com/principles/#liskov-substitution-principle) en montrant qu'il peut accepter tous les visiteurs alors qu'il ne s'intéresse en réalité qu'à certains d'entre eux.
* Une hiérarchie parallèle de visiteurs doit être créée pour tous les membres de la hiérarchie des classes visitables.
## Patron de conception associé
* [Pqtron de conception Visitor](https://java-design-patterns.com/patterns/visitor/)
## Crédits
* [Acyclic Visitor by Robert C. Martin](http://condor.depaul.edu/dmumaugh/OOT/Design-Principles/acv.pdf)
* [Acyclic Visitor in WikiWikiWeb](https://wiki.c2.com/?AcyclicVisitor)
+137
View File
@@ -0,0 +1,137 @@
---
title: Adapter
category: Structural
language: fr
tag:
- Gang of Four
---
## Également connu sous le nom de
Wrapper
## Intention
Convertir l'interface d'une classe en une autre interface attendue par les clients. Adapter permet à des classes de travailler ensemble
qui ne pourraient pas fonctionner autrement en raison d'interfaces incompatibles.
## Explication
Exemple concrêt
> Supposons que vous avez des photos sur votre carte mémoire et vous devez les transférer sur votre ordinateur. Pour ce faire, vous avez besoin d'un adaptateur qui est compatible aux ports de votre ordinateur pour vous permettre de connecter votre carte memoire à l'ordinateur. dans ce cas le lecteur de carte est un adapteur.
> Un autre exemple serait le fameux adaptateur électrique ; une fiche à trois branches ne peut pas être branchée sur une prise à deux branches, elle doit utiliser un adaptateur électrique qui la rend compatible avec les prises à deux branches.
> Un autre exemple serait celui d'un traducteur qui traduirait les mots prononcés par une personne à une autre.
En clair
> Le patron adapter permet d'envelopper un objet autrement incompatible dans un adaptateur afin de le rendre compatible avec une autre classe.
Wikipedia dit
> En génie logiciel, le pattron de conception adapter est un pattron de conception logicielle qui permet d'utiliser l'interface d'une classe existante comme une autre interface. Il est souvent utilisé pour faire fonctionner des classes existantes avec d'autres sans modifier leur code source.
**Exemple de programme**
Prenons l'exemple d'un capitaine qui ne peut utiliser que des bateaux à rames et qui ne peut pas du tout naviguer.
Tout d'abord, nous avons les interfaces `RowingBoat` et `FishingBoat`
```java
public interface RowingBoat {
void row();
}
@Slf4j
public class FishingBoat {
public void sail() {
LOGGER.info("The fishing boat is sailing");
}
}
```
Et le capitaine s'attend à ce qu'une implémentation de l'interface `RowingBoat` soit capable de se déplacer
```java
public class Captain {
private final RowingBoat rowingBoat;
// default constructor and setter for rowingBoat
public Captain(RowingBoat rowingBoat) {
this.rowingBoat = rowingBoat;
}
public void row() {
rowingBoat.row();
}
}
```
Supposons maintenant que les pirates arrivent et que notre capitaine doive s'échapper, mais qu'il ne dispose que d'un bateau de pêche. Nous devons créer un adaptateur qui permette au capitaine de faire fonctionner le bateau de pêche avec ses compétences de rameur.
```java
@Slf4j
public class FishingBoatAdapter implements RowingBoat {
private final FishingBoat boat;
public FishingBoatAdapter() {
boat = new FishingBoat();
}
@Override
public void row() {
boat.sail();
}
}
```
Et maintenant, `Captain` peut utiliser le `FishingBoat` pour échapper aux pirates.
```java
var captain = new Captain(new FishingBoatAdapter());
captain.row();
```
## Diagramme des classes
![alt text](../../../adapter/etc/adapter.urm.png "Adapter class diagram")
## Application
Utiliser le pattron de conception adapter lorsque
* Vous souhaitez utiliser une classe existante, mais son interface ne correspond pas à celle dont vous avez besoin
* Vous souhaitez créer une classe réutilisable qui coopère avec des classes non liées ou imprévues, c'est-à-dire des classes qui n'ont pas nécessairement d'interfaces compatibles.
* Vous devez utiliser plusieurs sous-classes existantes, mais il n'est pas pratique d'adapter leur interface en les sous-classant toutes. Un adaptateur d'objet peut adapter l'interface de sa classe mère.
* La plupart des applications utilisant des bibliothèques tierces utilisent des adaptateurs comme couche intermédiaire entre l'application et la bibliothèque tierce afin de découpler l'application de la bibliothèque. Si une autre bibliothèque doit être utilisée, il suffit de créer un adaptateur pour la nouvelle bibliothèque sans avoir à modifier le code de l'application.
## Tutoriels
* [Dzone](https://dzone.com/articles/adapter-design-pattern-in-java)
* [Refactoring Guru](https://refactoring.guru/design-patterns/adapter/java/example)
* [Baeldung](https://www.baeldung.com/java-adapter-pattern)
## Conséquences
Les adaptateurs de classe et d'objet présentent différents avantages. Un adaptateur de classe :
* Adapte l'adaptateur à la cible en s'engageant dans une classe concrète d'adaptateur. Par conséquent, un adaptateur de classe ne fonctionnera pas si nous voulons adapter une classe et toutes ses sous-classes.
* Permet à l'adaptateur de surcharger certains comportements de l'adaptaté puisque l'adaptateur est une sous-classe de l'adaptaté.
* N'introduit qu'un seul objet, et aucune indirection de pointeur supplémentaire n'est nécessaire pour accéder à l'adaptateur.
Un adaptateur d'objet :
* Permet à un seul adaptateur de travailler avec de nombreux adaptatés, c'est-à-dire l'adaptateur lui-même et toutes ses sous-classes (le cas échéant). L'adaptateur peut également ajouter des fonctionnalités à tous les adaptatés en même temps.
* Rend plus difficile la modification du comportement de l'adapté. Il faudra créer des sous classes de l'adapta et faire en sorte que l'adaptateur se réfère à la sous-classe plutôt qu'à l'adapté lui-même.
## Utilisations connues
* [java.util.Arrays#asList()](http://docs.oracle.com/javase/8/docs/api/java/util/Arrays.html#asList%28T...%29)
* [java.util.Collections#list()](https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#list-java.util.Enumeration-)
* [java.util.Collections#enumeration()](https://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#enumeration-java.util.Collection-)
* [javax.xml.bind.annotation.adapters.XMLAdapter](http://docs.oracle.com/javase/8/docs/api/javax/xml/bind/annotation/adapters/XmlAdapter.html#marshal-BoundType-)
## Crédits
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)
* [J2EE Design Patterns](https://www.amazon.com/gp/product/0596004273/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596004273&linkCode=as2&tag=javadesignpat-20&linkId=48d37c67fb3d845b802fa9b619ad8f31)
* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b)
* [Refactoring to Patterns](https://www.amazon.com/gp/product/0321213351/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0321213351&linkCode=as2&tag=javadesignpat-20&linkId=2a76fcb387234bc71b1c61150b3cc3a7)
@@ -0,0 +1,106 @@
---
title: Aggregator Microservices
category: Architectural
language: fr
tag:
- Cloud distributed
- Decoupling
- Microservices
---
## Intention
L'utilisateur fait un appel unique au service d'agrégation, et ce dernier appelle ensuite chaque microservice approprié.
## Explication
Exemple concret
> Notre marché en ligne a besoin d'informations sur les produits et leur stock actuel. Elle fait appel à un service
> d'agrégation qui, à son tour, appelle le microservice d'information sur les produits et le microservice d'inventaire
> des produits et renvoie les informations combinées.
En clair
> Aggregator Microservice collecte des éléments de données provenant de divers microservices et renvoie un agrégat pour traitement..
Stack Overflow dit
> Aggregator Microservice invoque plusieurs services pour réaliser la fonctionnalité requise par l'application.
**Exemple de programme**
Commençons par le modèle de données. Voici notre `Product`.
```java
public class Product {
private String title;
private int productInventories;
// getters and setters ->
...
}
```
Ensuite, nous pouvons présenter notre microservice `Aggregator`. Il contient les clients `ProductInformationClient` et
`ProductInventoryClient` pour appeler les microservices respectifs.
```java
@RestController
public class Aggregator {
@Resource
private ProductInformationClient informationClient;
@Resource
private ProductInventoryClient inventoryClient;
@RequestMapping(path = "/product", method = RequestMethod.GET)
public Product getProduct() {
var product = new Product();
var productTitle = informationClient.getProductTitle();
var productInventory = inventoryClient.getProductInventories();
//Fallback to error message
product.setTitle(requireNonNullElse(productTitle, "Error: Fetching Product Title Failed"));
//Fallback to default error inventory
product.setProductInventories(requireNonNullElse(productInventory, -1));
return product;
}
}
```
Voici l'essentiel de la mise en œuvre du microservice d'information. Le microservice dInventory est similaire, il renvoie simplement l'inventaire.
```java
@RestController
public class InformationController {
@RequestMapping(value = "/information", method = RequestMethod.GET)
public String getProductTitle() {
return "The Product Title.";
}
}
```
L'appel à notre API REST `Aggregator` renvoie les informations sur le produit.
```bash
curl http://localhost:50004/product
{"title":"The Product Title.","productInventories":5}
```
## Class diagram
![alt text](../../../aggregator-microservices/aggregator-service/etc/aggregator-service.png "Aggregator Microservice")
## Application
Utilisez le modèle de microservices agrégateur lorsque vous avez besoin d'une API unifiée pour différents microservices, quel que soit l'appareil client.
## Crédits
* [Microservice Design Patterns](http://web.archive.org/web/20190705163602/http://blog.arungupta.me/microservice-design-patterns/)
* [Microservices Patterns: With examples in Java](https://www.amazon.com/gp/product/1617294543/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617294543&linkId=8b4e570267bc5fb8b8189917b461dc60)
* [Architectural Patterns: Uncover essential patterns in the most indispensable realm of enterprise architecture](https://www.amazon.com/gp/product/B077T7V8RC/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=B077T7V8RC&linkId=c34d204bfe1b277914b420189f09c1a4)
+204
View File
@@ -0,0 +1,204 @@
---
title: Ambassador
category: Structural
language: fr
tag:
- Decoupling
- Cloud distributed
---
## Intention
Fournir une instance de service d'assistance à un client et décharger une fonctionnalité commune d'une ressource partagée.
## Explication
Exemple concret
> Un service distant a de nombreux clients qui accèdent à une fonction qu'il fournit. Le service est une application
> ancienne qu'il est impossible de mettre à jour. Le grand nombre de requêtes des utilisateurs entraîne des problèmes de
> connectivité. De nouvelles règles relatives à la fréquence des requêtes doivent être mises en œuvre, ainsi que des
> contrôles de latence et une journalisation côté client.
En clair
>Avec le modèle Ambassador, nous pouvons mettre en œuvre des interrogations moins fréquentes de la part des clients,
> ainsi que des contrôles de latence et une journalisation.
La documentation de Microsoft indique que
> Un service ambassadeur peut être considéré comme un mandataire hors processus qui se trouve au même endroit que le client.
> Ce pattron peut être utile pour décharger les tâches courantes de connectivité client telles que la surveillance,
> la journalisation, le routage, la sécurité (comme TLS) et les modèles de résilience d'une manière indépendante du langage.
> Il est souvent utilisé avec des applications anciennes ou d'autres applications difficiles à modifier, afin d'étendre
> leurs capacités de mise en réseau. Il peut également permettre à une équipe spécialisée de mettre en œuvre ces fonctionnalités.
**Exemple de programme**
En gardant en mémoire l'introduction ci-dessus, nous reproduirons cette fonctionnalité dans ce exemple. Nous avons une interface
implémentée par un service distant aussi bien que service ambassadeur
We have an interface implemented
by the remote service as well as the ambassador service :
```java
interface RemoteServiceInterface {
long doRemoteFunction(int value) throws Exception;
}
```
Un sercive distant représenté comme un singleton.
```java
@Slf4j
public class RemoteService implements RemoteServiceInterface {
private static RemoteService service = null;
static synchronized RemoteService getRemoteService() {
if (service == null) {
service = new RemoteService();
}
return service;
}
private RemoteService() {}
@Override
public long doRemoteFunction(int value) {
long waitTime = (long) Math.floor(Math.random() * 1000);
try {
sleep(waitTime);
} catch (InterruptedException e) {
LOGGER.error("Thread sleep interrupted", e);
}
return waitTime >= 200 ? value * 10 : -1;
}
}
```
Un service ambassadeur ajoute des fonctionnalités supplémentaires à l'instar de la journalisation et des contrôles de latence
```java
@Slf4j
public class ServiceAmbassador implements RemoteServiceInterface {
private static final int RETRIES = 3;
private static final int DELAY_MS = 3000;
ServiceAmbassador() {
}
@Override
public long doRemoteFunction(int value) {
return safeCall(value);
}
private long checkLatency(int value) {
var startTime = System.currentTimeMillis();
var result = RemoteService.getRemoteService().doRemoteFunction(value);
var timeTaken = System.currentTimeMillis() - startTime;
LOGGER.info("Time taken (ms): " + timeTaken);
return result;
}
private long safeCall(int value) {
var retries = 0;
var result = (long) FAILURE;
for (int i = 0; i < RETRIES; i++) {
if (retries >= RETRIES) {
return FAILURE;
}
if ((result = checkLatency(value)) == FAILURE) {
LOGGER.info("Failed to reach remote: (" + (i + 1) + ")");
retries++;
try {
sleep(DELAY_MS);
} catch (InterruptedException e) {
LOGGER.error("Thread sleep state interrupted", e);
}
} else {
break;
}
}
return result;
}
}
```
Un client dispose d'un service ambassadeur local utilisé pour interagir avec le service distant :
```java
@Slf4j
public class Client {
private final ServiceAmbassador serviceAmbassador = new ServiceAmbassador();
long useService(int value) {
var result = serviceAmbassador.doRemoteFunction(value);
LOGGER.info("Service result: " + result);
return result;
}
}
```
Voici deux clients utilisant le service.
```java
public class App {
public static void main(String[] args) {
var host1 = new Client();
var host2 = new Client();
host1.useService(12);
host2.useService(73);
}
}
```
Ci-déssous la sortie du programme :
```java
Time taken (ms): 111
Service result: 120
Time taken (ms): 931
Failed to reach remote: (1)
Time taken (ms): 665
Failed to reach remote: (2)
Time taken (ms): 538
Failed to reach remote: (3)
Service result: -1
```
## Class diagram
![alt text](../../../ambassador/etc/ambassador.urm.png "Ambassador class diagram")
## Application
* Le pattron ambassador s'applique lorsque l'on travaille avec un service distant existant qui ne peut pas être modifié ou
qui serait extrêmement difficile à modifier. Les fonctions de connectivité peuvent être mises en œuvre sur le client sans
qu'il soit nécessaire d'apporter des modifications au service distant.
* Ambassador fournit une interface locale pour un service distant.
* Ambassador assure la journalisation, la coupure de circuit, les tentatives et la sécurité sur le client.
## Cas d'utilisation typique
* Contrôler l'accès à un autre objet
* Mise en œuvre de la journalisation
* Mettre en œuvre d'un coupe-circuit
* Décharger les tâches de service à distance
* Faciliter la connexion au réseau
## Utilisations connues
* [Kubernetes-native API gateway for microservices](https://github.com/datawire/ambassador)
## Modèles connexes
* [Proxy](https://java-design-patterns.com/patterns/proxy/)
## Crédits
* [Ambassador pattern](https://docs.microsoft.com/en-us/azure/architecture/patterns/ambassador)
* [Designing Distributed Systems: Patterns and Paradigms for Scalable, Reliable Services](https://www.amazon.com/s?k=designing+distributed+systems&sprefix=designing+distri%2Caps%2C156&linkCode=ll2&tag=javadesignpat-20&linkId=a12581e625462f9038557b01794e5341&language=en_US&ref_=as_li_ss_tl)
+164
View File
@@ -0,0 +1,164 @@
---
title: API Gateway
category: Architectural
language: fr
tag:
- Cloud distributed
- Decoupling
- Microservices
---
## Intention
Regrouper les appels aux microservices en un seul endroit, la passerelle API.
L'utilisateur fait un seul appel à la passerelle API, qui appelle ensuite chaque microservice concerné.
## Explication
Avec les pattrons microservices, un client peut avoir besoin de données provenant de plusieurs microservices différents.
Si le client appelait directement chaque microservice, cela pourrait contribuer à allonger les temps de chargement,
puisque le client devrait faire une requete réseau pour chaque microservice appelé. En outre, le fait que le client appelle
chaque microservice directement le lie à ce microservice - si les implémentations internes des microservices changent
(par exemple, si deux microservices sont combinés) ou si l'emplacement (hôte et port) d'un microservice change,
alors chaque client qui utilise ces microservices doit être informé de l'existence de ce microservice.
L'objectif du pattron API Gateway est d'atténuer certains de ces problèmes. Dans le pattron API Gateway une entité supplémentaire
(la passerelle API) est placée entre le client et les microservices. Le rôle de la passerelle API est d'agréger les appels aux microservices. Plutôt que le client
appelle chaque microservice individuellement, le client appelle la passerelle API une seule fois.
La passerelle API appelle alors chacun des microservices dont le client a besoin.
Exemple concret
> Nous mettons en œuvre des microservices et un pattron API Gateway pour un site de commerce en ligne.
> Dans ce système la passerelle API fait des appels aux microservices Image et Prix.
En clair
> Pour un système mis en œuvre à l'aide d'une architecture de microservices,
> API Gateway est le point d'entrée unique qui regroupe les appels aux différents microservices.
Wikipedia dit
> La passerelle API est un serveur qui agit comme un front-end API, reçoit les requêtes API, applique des politiques de
> limitation et de sécurité, transmet les requêtes au service back-end et renvoie la réponse au demandeur.
> Une passerelle comprend souvent un moteur de transformation pour orchestrer et modifier les demandes et les réponses à la volée.
> Une passerelle peut également fournir des fonctionnalités telles que la collecte de données analytiques et la mise en cache.
> La passerelle peut fournir des fonctionnalités pour prendre en charge l'authentification, l'autorisation, la sécurité,
> l'audit et la conformité réglementaire.
**Exemple de programme**
Cette mise en œuvre montre à quoi pourrait ressembler le pattron de conception API Gateway pour un site de commerce électronique.
La passerelle `ApiGateway` fait des appels aux microservices Image et Price en utilisant respectivement `ImageClientImpl` et `PriceClientImpl` respectivement.
Les clients qui consultent le site sur un ordinateur de bureau peuvent voir à la fois les informations sur le prix et l'image d'un produit.
Les clients qui consultent le site sur un ordinateur de bureau peuvent voir à la fois des informations sur le prix et l'image d'un produit,
donc la passerelle appelle les deux microservices et regroupe les données dans le modèle `DesktopProduct`.
Cependant, les utilisateurs mobiles ne voient que les informations sur le prix ; Ils ne voient pas l'image du produit.
Pour les utilisateurs mobiles, la passerelle `ApiGateway` ne récupère que les informations de prix, qu'elle utilise pour remplir le modèle `MobileProduct`.
Voici l'implémentation du microservice Image.
```java
public interface ImageClient {
String getImagePath();
}
public class ImageClientImpl implements ImageClient {
@Override
public String getImagePath() {
var httpClient = HttpClient.newHttpClient();
var httpGet = HttpRequest.newBuilder()
.GET()
.uri(URI.create("http://localhost:50005/image-path"))
.build();
try {
var httpResponse = httpClient.send(httpGet, BodyHandlers.ofString());
return httpResponse.body();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
return null;
}
}
```
Voici l'implémentation du microservice Price.
```java
public interface PriceClient {
String getPrice();
}
public class PriceClientImpl implements PriceClient {
@Override
public String getPrice() {
var httpClient = HttpClient.newHttpClient();
var httpGet = HttpRequest.newBuilder()
.GET()
.uri(URI.create("http://localhost:50006/price"))
.build();
try {
var httpResponse = httpClient.send(httpGet, BodyHandlers.ofString());
return httpResponse.body();
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
return null;
}
}
```
Nous voyons ici comment API Gateway fait correspondre les demandes aux microservices.
```java
public class ApiGateway {
@Resource
private ImageClient imageClient;
@Resource
private PriceClient priceClient;
@RequestMapping(path = "/desktop", method = RequestMethod.GET)
public DesktopProduct getProductDesktop() {
var desktopProduct = new DesktopProduct();
desktopProduct.setImagePath(imageClient.getImagePath());
desktopProduct.setPrice(priceClient.getPrice());
return desktopProduct;
}
@RequestMapping(path = "/mobile", method = RequestMethod.GET)
public MobileProduct getProductMobile() {
var mobileProduct = new MobileProduct();
mobileProduct.setPrice(priceClient.getPrice());
return mobileProduct;
}
}
```
## Diagramme de clqsses
![alt text](../../../api-gateway/etc/api-gateway.png "API Gateway")
## Application
Utilisez le pattron de passerelle API lorsque
* Vous utilisez une architecture de microservices et avez besoin d'un point d'agrégation unique pour vos appels de microservices.
## Tutoriels
* [Exploring the New Spring Cloud Gateway](https://www.baeldung.com/spring-cloud-gateway)
* [Spring Cloud - Gateway](https://www.tutorialspoint.com/spring_cloud/spring_cloud_gateway.htm)
* [Getting Started With Spring Cloud Gateway](https://dzone.com/articles/getting-started-with-spring-cloud-gateway)
## Crédits
* [microservices.io - API Gateway](http://microservices.io/patterns/apigateway.html)
* [NGINX - Building Microservices: Using an API Gateway](https://www.nginx.com/blog/building-microservices-using-an-api-gateway/)
* [Microservices Patterns: With examples in Java](https://www.amazon.com/gp/product/1617294543/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617294543&linkId=ac7b6a57f866ac006a309d9086e8cfbd)
* [Building Microservices: Designing Fine-Grained Systems](https://www.amazon.com/gp/product/1491950358/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1491950358&linkId=4c95ca9831e05e3f0dadb08841d77bf1)
@@ -0,0 +1,140 @@
---
title: Arrange/Act/Assert
category: Idiom
language: fr
tag:
- Testing
---
## Aussi connu sous le nom de
Given/When/Then
## Intention
Arrange/Act/Assert (AAA) est un pattron d'organisation des tests unitaires.
Il décompose les tests en trois étapes claires et distinctes :
1. Arrange : éffectuer la configuration et l'initialisation requises pour le test.
2. Act : éffectuer la ou les actions requises pour le test.
3. Assert: Vérifier le(s) résultat(s) du test.
## Explication
Ce pattron présente plusieurs avantages importants. Il crée une séparation claire entre la mise en place d'un test d'un test,
les opérations et les résultats. Cette structure rend le code plus facile à lire et à comprendre.
Si vous placez les étapes dans l'ordre et que vous formatez votre code source pour les séparer, vous pouvez parcourir un test et comprendre rapidement ce qu'il fait.
Il impose également un certain degré de discipline lors de l'écriture des tests. Vous devez penser clairement les trois étapes de votre test.
Il est plus naturel d'écrire les tests en même temps, puisque vous avez déjà un plan.
Exemple
> Pour écrire des tests unitaire clairs et compréhensibles.
En clair
> Arrange/Act/Assert est un pattron de conception de tests qui organise les tests en trois étapes pour une maintenance facile.
WikiWikiWeb dit
> Arrange/Act/Assert est un pattron pour organiser et formater un code dans les methodes de test unitaire.
**Exemple de programme**
Commençons par présenter notre classe `Cash` qui subira un test unitaire.
```java
public class Cash {
private int amount;
Cash(int amount) {
this.amount = amount;
}
void plus(int addend) {
amount += addend;
}
boolean minus(int subtrahend) {
if (amount >= subtrahend) {
amount -= subtrahend;
return true;
} else {
return false;
}
}
int count() {
return amount;
}
}
```
Ensuite, nous rédigeons nos tests unitaires suivant le pattron Arrange/Act/Assert.
Notez les étapes clairement séparées pour chaque test unitaire.
```java
class CashAAATest {
@Test
void testPlus() {
//Arrange
var cash = new Cash(3);
//Act
cash.plus(4);
//Assert
assertEquals(7, cash.count());
}
@Test
void testMinus() {
//Arrange
var cash = new Cash(8);
//Act
var result = cash.minus(5);
//Assert
assertTrue(result);
assertEquals(3, cash.count());
}
@Test
void testInsufficientMinus() {
//Arrange
var cash = new Cash(1);
//Act
var result = cash.minus(6);
//Assert
assertFalse(result);
assertEquals(1, cash.count());
}
@Test
void testUpdate() {
//Arrange
var cash = new Cash(5);
//Act
cash.plus(6);
var result = cash.minus(3);
//Assert
assertTrue(result);
assertEquals(8, cash.count());
}
}
```
## Application
Le pattron Arrange/Act/Assert peut être utilisé lorsque :
* Vous avez besoin d'organiser vos tests unitaire pour qu'il soit facile à lire, maintenir et améliorer.
## Crédits
* [Arrange, Act, Assert: What is AAA Testing?](https://blog.ncrunch.net/post/arrange-act-assert-aaa-testing.aspx)
* [Bill Wake: 3A Arrange, Act, Assert](https://xp123.com/articles/3a-arrange-act-assert/)
* [Martin Fowler: GivenWhenThen](https://martinfowler.com/bliki/GivenWhenThen.html)
* [xUnit Test Patterns: Refactoring Test Code](https://www.amazon.com/gp/product/0131495054/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0131495054&linkId=99701e8f4af2f7e8dd50d720c9b63dbf)
* [Unit Testing Principles, Practices, and Patterns](https://www.amazon.com/gp/product/1617296279/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=1617296279&linkId=74c75cf22a63c3e4758ae08aa0a0cc35)
* [Test Driven Development: By Example](https://www.amazon.com/gp/product/0321146530/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0321146530&linkId=5c63a93d8c1175b84ca5087472ef0e05)
@@ -0,0 +1,166 @@
---
title: Async Method Invocation
category: Concurrency
language: fr
tag:
- Reactive
---
## Intention
Le pattron de conception Asynchronous method invocation est un pattron dans lequel le thread appelé n'est pas bloqué en
attendant la fin de l'exécution des tâches.
Ce pattron permet le traitement parallèle de plusieurs tâches indépendantes et récupère les résultats via les callback ou patiente jusqu'à la fin.
## Explication
Exemple concret
> Le lancement de fusées spatiales est une activité passionnante. Le commandant de la mission donne
> l'ordre de lancement et, après un temps indéterminé, la fusée réussit son lancement ou échoue lamentablement.
En clair
> Asynchronous method invocation démarre l'exécution de la tâche et retourne directement avant la fin de l'exécution de la tâche.
> Les résultats de l'exécution des tâches sont retournés après.
Wikipedia dit
> Dans la programmation multithread, asynchronous method invocation (AMI), également connue sous le nom de asynchronous method calls
> ou le pattron asynchronous, est un pattron de conception dans lequel le site d'appel n'est pas bloqué en attendant que le code appelé se termine.
> Au lieu de cela, le thread appelant est informé de l'arrivée de la réponse. L'interrogation pour une réponse est une option non souhaitée.
**Exemple de programme**
Dans cet exemple, nous lançons des fusées spatiales et déployons des rovers lunaires.
L'application démontre le pattron async method invocation. Les éléments clés de ce modèle sont `AsyncResult`
qui est un conteneur intermédiaire pour une valeur évaluée de manière asynchrone, `AsyncCallback` qui peut être fourni
pour être exécuté à la fin de la tâche et `AsyncExecutor` qui gère l'exécution des tâches asynchrones. qui gère l'exécution des tâches asynchrones.
```java
public interface AsyncResult<T> {
boolean isCompleted();
T getValue() throws ExecutionException;
void await() throws InterruptedException;
}
```
```java
public interface AsyncCallback<T> {
void onComplete(T value, Optional<Exception> ex);
}
```
```java
public interface AsyncExecutor {
<T> AsyncResult<T> startProcess(Callable<T> task);
<T> AsyncResult<T> startProcess(Callable<T> task, AsyncCallback<T> callback);
<T> T endProcess(AsyncResult<T> asyncResult) throws ExecutionException, InterruptedException;
}
```
`ThreadAsyncExecutor` est une implémentation de `AsyncExecutor`. Certains de ses éléments clés sont décrits ci-dessous.
```java
public class ThreadAsyncExecutor implements AsyncExecutor {
@Override
public <T> AsyncResult<T> startProcess(Callable<T> task) {
return startProcess(task, null);
}
@Override
public <T> AsyncResult<T> startProcess(Callable<T> task, AsyncCallback<T> callback) {
var result = new CompletableResult<>(callback);
new Thread(
() -> {
try {
result.setValue(task.call());
} catch (Exception ex) {
result.setException(ex);
}
},
"executor-" + idx.incrementAndGet())
.start();
return result;
}
@Override
public <T> T endProcess(AsyncResult<T> asyncResult)
throws ExecutionException, InterruptedException {
if (!asyncResult.isCompleted()) {
asyncResult.await();
}
return asyncResult.getValue();
}
}
```
Nous sommes ensuite prêts à lancer quelques fusées pour voir comment tout fonctionne ensemble.
```java
public static void main(String[] args) throws Exception {
// construct a new executor that will run async tasks
var executor = new ThreadAsyncExecutor();
// start few async tasks with varying processing times, two last with callback handlers
final var asyncResult1 = executor.startProcess(lazyval(10, 500));
final var asyncResult2 = executor.startProcess(lazyval("test", 300));
final var asyncResult3 = executor.startProcess(lazyval(50L, 700));
final var asyncResult4 = executor.startProcess(lazyval(20, 400), callback("Deploying lunar rover"));
final var asyncResult5 =
executor.startProcess(lazyval("callback", 600), callback("Deploying lunar rover"));
// emulate processing in the current thread while async tasks are running in their own threads
Thread.sleep(350); // Oh boy, we are working hard here
log("Mission command is sipping coffee");
// wait for completion of the tasks
final var result1 = executor.endProcess(asyncResult1);
final var result2 = executor.endProcess(asyncResult2);
final var result3 = executor.endProcess(asyncResult3);
asyncResult4.await();
asyncResult5.await();
// log the results of the tasks, callbacks log immediately when complete
log("Space rocket <" + result1 + "> launch complete");
log("Space rocket <" + result2 + "> launch complete");
log("Space rocket <" + result3 + "> launch complete");
}
```
Voici la sortie de la console du programme.
```java
21:47:08.227 [executor-2] INFO com.iluwatar.async.method.invocation.App - Space rocket <test> launched successfully
21:47:08.269 [main] INFO com.iluwatar.async.method.invocation.App - Mission command is sipping coffee
21:47:08.318 [executor-4] INFO com.iluwatar.async.method.invocation.App - Space rocket <20> launched successfully
21:47:08.335 [executor-4] INFO com.iluwatar.async.method.invocation.App - Deploying lunar rover <20>
21:47:08.414 [executor-1] INFO com.iluwatar.async.method.invocation.App - Space rocket <10> launched successfully
21:47:08.519 [executor-5] INFO com.iluwatar.async.method.invocation.App - Space rocket <callback> launched successfully
21:47:08.519 [executor-5] INFO com.iluwatar.async.method.invocation.App - Deploying lunar rover <callback>
21:47:08.616 [executor-3] INFO com.iluwatar.async.method.invocation.App - Space rocket <50> launched successfully
21:47:08.617 [main] INFO com.iluwatar.async.method.invocation.App - Space rocket <10> launch complete
21:47:08.617 [main] INFO com.iluwatar.async.method.invocation.App - Space rocket <test> launch complete
21:47:08.618 [main] INFO com.iluwatar.async.method.invocation.App - Space rocket <50> launch complete
```
# Diagramme de classes
![alt text](../../../async-method-invocation/etc/async-method-invocation.png "Async Method Invocation")
## Application
Utilisez le pattron async method invocation lorsque
* Vous avez plusieurs tâches indépendantes qui peuvent être exécutées en parallèle
* Vous devez améliorer les performances d'un groupe de tâches séquentielles
* Vous disposez d'une capacité de traitement limitée ou de tâches à long terme et l'appelant ne doit pas attendre que les tâches soient exécutées.
## Application concrete
* [FutureTask](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/FutureTask.html)
* [CompletableFuture](https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html)
* [ExecutorService](http://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ExecutorService.html)
* [Task-based Asynchronous Pattern](https://msdn.microsoft.com/en-us/library/hh873175.aspx)
+133
View File
@@ -0,0 +1,133 @@
---
title: Balking
category: Concurrency
language: fr
tag:
- Decoupling
---
## Intention
Le pattron de conception Balking est utilisé pour empêcher un objet d'exécuter un certain code
s'il est dans un état incomplet ou inapproprié.
## Explication
Exemple concret
> Sur une machine à laver, un bouton de démarrage permet de lancer le lavage du linge. Lorsque la machine à laver est inactive,
> le bouton fonctionne comme prévu, mais si la machine est déjà en train de laver, le bouton ne fait rien.
En clair
> En utilisant le pattron balking, un certain code ne s'exécute que si l'objet se trouve dans un état particulier.
Wikipedia dit
> Le pattron de conception balking est un pattron de conception de logiciel qui n'exécute une action sur un objet que
> lorsque l'objet se trouve dans un état particulier. Par exemple, si un objet lit des fichiers ZIP et qu'une méthode
> appelante invoque une méthode get sur l'objet alors que le fichier ZIP n'est pas ouvert, l'objet rejette la demande.
**Exemple de programme**
Dans cet exemple d'implémentation, `WashingMachine` est un objet qui peut être dans deux états : ENABLED et WASHING.
Si la machine est ENABLED, l'état change en WASHING en utilisant une méthode thread-safe. D'autre part, si elle a déjà
été lavée et qu'un autre thread exécute `wash()`, elle ne le fera pas et terminera sans rien faire.
Voici les parties pertinentes de la classe `WashingMachine`
```java
@Slf4j
public class WashingMachine {
private final DelayProvider delayProvider;
private WashingMachineState washingMachineState;
public WashingMachine(DelayProvider delayProvider) {
this.delayProvider = delayProvider;
this.washingMachineState = WashingMachineState.ENABLED;
}
public WashingMachineState getWashingMachineState() {
return washingMachineState;
}
public void wash() {
synchronized (this) {
var machineState = getWashingMachineState();
LOGGER.info("{}: Actual machine state: {}", Thread.currentThread().getName(), machineState);
if (this.washingMachineState == WashingMachineState.WASHING) {
LOGGER.error("Cannot wash if the machine has been already washing!");
return;
}
this.washingMachineState = WashingMachineState.WASHING;
}
LOGGER.info("{}: Doing the washing", Thread.currentThread().getName());
this.delayProvider.executeAfterDelay(50, TimeUnit.MILLISECONDS, this::endOfWashing);
}
public synchronized void endOfWashing() {
washingMachineState = WashingMachineState.ENABLED;
LOGGER.info("{}: Washing completed.", Thread.currentThread().getId());
}
}
```
Voici l'interface simple `DelayProvider` utilisée par le `WashingMachine`.
```java
public interface DelayProvider {
void executeAfterDelay(long interval, TimeUnit timeUnit, Runnable task);
}
```
Nous allons maintenant présenter l'application en utilisant le `WashingMachine`.
```java
public static void main(String... args) {
final var washingMachine = new WashingMachine();
var executorService = Executors.newFixedThreadPool(3);
for (int i = 0; i < 3; i++) {
executorService.execute(washingMachine::wash);
}
executorService.shutdown();
try {
executorService.awaitTermination(10, TimeUnit.SECONDS);
} catch (InterruptedException ie) {
LOGGER.error("ERROR: Waiting on executor service shutdown!");
Thread.currentThread().interrupt();
}
}
```
Voici la sortie de la console du programme.
```
14:02:52.268 [pool-1-thread-2] INFO com.iluwatar.balking.WashingMachine - pool-1-thread-2: Actual machine state: ENABLED
14:02:52.272 [pool-1-thread-2] INFO com.iluwatar.balking.WashingMachine - pool-1-thread-2: Doing the washing
14:02:52.272 [pool-1-thread-3] INFO com.iluwatar.balking.WashingMachine - pool-1-thread-3: Actual machine state: WASHING
14:02:52.273 [pool-1-thread-3] ERROR com.iluwatar.balking.WashingMachine - Cannot wash if the machine has been already washing!
14:02:52.273 [pool-1-thread-1] INFO com.iluwatar.balking.WashingMachine - pool-1-thread-1: Actual machine state: WASHING
14:02:52.273 [pool-1-thread-1] ERROR com.iluwatar.balking.WashingMachine - Cannot wash if the machine has been already washing!
14:02:52.324 [pool-1-thread-2] INFO com.iluwatar.balking.WashingMachine - 14: Washing completed.
```
## Diagramme de classe
![alt text](../../../balking/etc/balking.png "Balking")
## Application
Utilisé le pattron balking lorsque :
* Vous souhaitez invoquer une action sur un objet uniquement lorsqu'il se trouve dans un état spécifique
* Les objets ne sont généralement que dans un état susceptible d'évoluer temporairement, mais pour une durée inconnue.
## Pattron de conception apparentés
* [Guarded Suspension Pattern](https://java-design-patterns.com/patterns/guarded-suspension/)
* [Double Checked Locking Pattern](https://java-design-patterns.com/patterns/double-checked-locking/)
## Crédits
* [Patterns in Java: A Catalog of Reusable Design Patterns Illustrated with UML, 2nd Edition, Volume 1](https://www.amazon.com/gp/product/0471227293/ref=as_li_qf_asin_il_tl?ie=UTF8&tag=javadesignpat-20&creative=9325&linkCode=as2&creativeASIN=0471227293&linkId=0e39a59ffaab93fb476036fecb637b99)
+215
View File
@@ -0,0 +1,215 @@
---
title: Bridge
category: Structural
language: fr
tag:
- Gang of Four
---
## Également connu sous le nom de
Handle/Body
## Intention
Découpler une abstraction de son implémentation afin que les deux puissent varier indépendamment.
## Explication
Exemple concret
> Considérons que vous avez une arme avec différents enchantements, et que vous êtes censé permettre de mélanger
> différentes armes avec différents enchantements. Que feriez-vous ? Créer plusieurs copies de chaque arme pour chacun
> des enchantements ou simplement créer un enchantement séparé et l'appliquer à l'arme en fonction des besoins ?
> Le pattron de concepetion Bridge pattern vous permet de faire la deuxième solution.
En clair
> Bridge pattern consiste à préférer la composition à l'héritage. Les détails de la mise en œuvre(implémentation)
> sont transférés d'une hiérarchie à un autre objet ayant une hiérarchie distincte.
Wikipedia dit
> Bridge pattern est un patron de conception utilisé en génie logiciel qui vise à "découpler une abstraction de sa
> mise en œuvre(son implémention) de manière à ce que les deux puissent varier de manière indépendante"
**Exemple de programme**
Servons nous de notre exemple d'arme ci-dessus. Nous avons ici la hiérarchie `Weapon` :
```java
public interface Weapon {
void wield();
void swing();
void unwield();
Enchantment getEnchantment();
}
public class Sword implements Weapon {
private final Enchantment enchantment;
public Sword(Enchantment enchantment) {
this.enchantment = enchantment;
}
@Override
public void wield() {
LOGGER.info("The sword is wielded.");
enchantment.onActivate();
}
@Override
public void swing() {
LOGGER.info("The sword is swinged.");
enchantment.apply();
}
@Override
public void unwield() {
LOGGER.info("The sword is unwielded.");
enchantment.onDeactivate();
}
@Override
public Enchantment getEnchantment() {
return enchantment;
}
}
public class Hammer implements Weapon {
private final Enchantment enchantment;
public Hammer(Enchantment enchantment) {
this.enchantment = enchantment;
}
@Override
public void wield() {
LOGGER.info("The hammer is wielded.");
enchantment.onActivate();
}
@Override
public void swing() {
LOGGER.info("The hammer is swinged.");
enchantment.apply();
}
@Override
public void unwield() {
LOGGER.info("The hammer is unwielded.");
enchantment.onDeactivate();
}
@Override
public Enchantment getEnchantment() {
return enchantment;
}
}
```
Voici la hiérarchie des enchantements distincts :
```java
public interface Enchantment {
void onActivate();
void apply();
void onDeactivate();
}
public class FlyingEnchantment implements Enchantment {
@Override
public void onActivate() {
LOGGER.info("The item begins to glow faintly.");
}
@Override
public void apply() {
LOGGER.info("The item flies and strikes the enemies finally returning to owner's hand.");
}
@Override
public void onDeactivate() {
LOGGER.info("The item's glow fades.");
}
}
public class SoulEatingEnchantment implements Enchantment {
@Override
public void onActivate() {
LOGGER.info("The item spreads bloodlust.");
}
@Override
public void apply() {
LOGGER.info("The item eats the soul of enemies.");
}
@Override
public void onDeactivate() {
LOGGER.info("Bloodlust slowly disappears.");
}
}
```
Voici les deux hiérarchies en action :
```java
LOGGER.info("The knight receives an enchanted sword.");
var enchantedSword = new Sword(new SoulEatingEnchantment());
enchantedSword.wield();
enchantedSword.swing();
enchantedSword.unwield();
LOGGER.info("The valkyrie receives an enchanted hammer.");
var hammer = new Hammer(new FlyingEnchantment());
hammer.wield();
hammer.swing();
hammer.unwield();
```
Voici la sortie de la console.
```
The knight receives an enchanted sword.
The sword is wielded.
The item spreads bloodlust.
The sword is swung.
The item eats the soul of enemies.
The sword is unwielded.
Bloodlust slowly disappears.
The valkyrie receives an enchanted hammer.
The hammer is wielded.
The item begins to glow faintly.
The hammer is swung.
The item flies and strikes the enemies finally returning to owner's hand.
The hammer is unwielded.
The item's glow fades.
```
## Diagramme de classes
![alt text](../../../bridge/etc/bridge.urm.png "Bridge class diagram")
## Application
Utilisez Bridge pattern lorsque
* Vous souhaitez éviter un lien permanent entre une abstraction et son implémentation. Cela peut être le cas, par exemple, lorsque l'implémentation doit être sélectionnée ou changée au moment de l'exécution.
* Les abstractions et leurs implémentations doivent être extensibles par des classes filles. Dans ce cas, Bridge pattern vous permet de combiner les différentes abstractions et implémentations et de les étendre indépendamment.
* Les changements dans l'implémentation d'une abstraction ne doivent pas avoir d'impact sur les clients, c'est-à-dire que leur code ne doit pas être recompilé.
* Vous avez une prolifération de classes. Une telle hiérarchie de classes indique la nécessité de diviser un objet en deux parties. Rumbaugh utilise le terme de "généralisations imbriquées" pour désigner de telles hiérarchies de classes.
* Vous souhaitez partager une implémentation entre plusieurs objets (peut-être en utilisant le comptage de références), et ce fait doit être caché au client. Un exemple simple est la classe String de Coplien, dans laquelle plusieurs objets peuvent partager la même représentation d'une chaîne de caractères.
## Tutoriel
* [Bridge Pattern Tutorial](https://www.journaldev.com/1491/bridge-design-pattern-java)
## Crédits
* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59)
* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b)