From 87a774c9d64988ccede63ceab3996d729837be32 Mon Sep 17 00:00:00 2001 From: believe Date: Sat, 27 Jan 2024 11:20:32 +0000 Subject: [PATCH] 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. --- localization/fr/abstract-document/README.md | 199 +++++++++++++++ localization/fr/abstract-factory/README.md | 227 ++++++++++++++++++ localization/fr/active-object/README.md | 128 ++++++++++ localization/fr/acyclic-visitore/README.md | 162 +++++++++++++ localization/fr/adapter/README.md | 137 +++++++++++ .../fr/aggregator-microservices/README.md | 106 ++++++++ localization/fr/ambassador/README.md | 204 ++++++++++++++++ localization/fr/api-gateway/README.md | 164 +++++++++++++ localization/fr/arrange-act-assert/README.md | 140 +++++++++++ .../fr/async-method-invocation/README.md | 166 +++++++++++++ localization/fr/balking/README.md | 133 ++++++++++ localization/fr/bridge/README.md | 215 +++++++++++++++++ 12 files changed, 1981 insertions(+) create mode 100644 localization/fr/abstract-document/README.md create mode 100644 localization/fr/abstract-factory/README.md create mode 100644 localization/fr/active-object/README.md create mode 100644 localization/fr/acyclic-visitore/README.md create mode 100644 localization/fr/adapter/README.md create mode 100644 localization/fr/aggregator-microservices/README.md create mode 100644 localization/fr/ambassador/README.md create mode 100644 localization/fr/api-gateway/README.md create mode 100644 localization/fr/arrange-act-assert/README.md create mode 100644 localization/fr/async-method-invocation/README.md create mode 100644 localization/fr/balking/README.md create mode 100644 localization/fr/bridge/README.md diff --git a/localization/fr/abstract-document/README.md b/localization/fr/abstract-document/README.md new file mode 100644 index 000000000..d55c51ea8 --- /dev/null +++ b/localization/fr/abstract-document/README.md @@ -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); + + Stream children(String key, Function, T> constructor); +} + +public abstract class AbstractDocument implements Document { + + private final Map properties; + + protected AbstractDocument(Map 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 Stream children(String key, Function, T> constructor) { + return Stream.ofNullable(get(key)) + .filter(Objects::nonNull) + .map(el -> (List>) 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 getType() { + return Optional.ofNullable((String) get(Property.TYPE.toString())); + } +} + +public interface HasPrice extends Document { + + default Optional getPrice() { + return Optional.ofNullable((Number) get(Property.PRICE.toString())); + } +} +public interface HasModel extends Document { + + default Optional getModel() { + return Optional.ofNullable((String) get(Property.MODEL.toString())); + } +} + +public interface HasParts extends Document { + + default Stream 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 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) diff --git a/localization/fr/abstract-factory/README.md b/localization/fr/abstract-factory/README.md new file mode 100644 index 000000000..e81c4ed2f --- /dev/null +++ b/localization/fr/abstract-factory/README.md @@ -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) diff --git a/localization/fr/active-object/README.md b/localization/fr/active-object/README.md new file mode 100644 index 000000000..0eae4af29 --- /dev/null +++ b/localization/fr/active-object/README.md @@ -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 requests; + + private String name; + + private Thread thread; + + public ActiveCreature(String name) { + this.name = name; + this.requests = new LinkedBlockingQueue(); + 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) \ No newline at end of file diff --git a/localization/fr/acyclic-visitore/README.md b/localization/fr/acyclic-visitore/README.md new file mode 100644 index 000000000..7e5b27e25 --- /dev/null +++ b/localization/fr/acyclic-visitore/README.md @@ -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) diff --git a/localization/fr/adapter/README.md b/localization/fr/adapter/README.md new file mode 100644 index 000000000..dfd85090a --- /dev/null +++ b/localization/fr/adapter/README.md @@ -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) diff --git a/localization/fr/aggregator-microservices/README.md b/localization/fr/aggregator-microservices/README.md new file mode 100644 index 000000000..ed27ca451 --- /dev/null +++ b/localization/fr/aggregator-microservices/README.md @@ -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) diff --git a/localization/fr/ambassador/README.md b/localization/fr/ambassador/README.md new file mode 100644 index 000000000..d0659a826 --- /dev/null +++ b/localization/fr/ambassador/README.md @@ -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) diff --git a/localization/fr/api-gateway/README.md b/localization/fr/api-gateway/README.md new file mode 100644 index 000000000..70e513e00 --- /dev/null +++ b/localization/fr/api-gateway/README.md @@ -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) diff --git a/localization/fr/arrange-act-assert/README.md b/localization/fr/arrange-act-assert/README.md new file mode 100644 index 000000000..f254878cb --- /dev/null +++ b/localization/fr/arrange-act-assert/README.md @@ -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) diff --git a/localization/fr/async-method-invocation/README.md b/localization/fr/async-method-invocation/README.md new file mode 100644 index 000000000..0eef955ad --- /dev/null +++ b/localization/fr/async-method-invocation/README.md @@ -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 { + boolean isCompleted(); + T getValue() throws ExecutionException; + void await() throws InterruptedException; +} +``` + +```java +public interface AsyncCallback { + void onComplete(T value, Optional ex); +} +``` + +```java +public interface AsyncExecutor { + AsyncResult startProcess(Callable task); + AsyncResult startProcess(Callable task, AsyncCallback callback); + T endProcess(AsyncResult 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 AsyncResult startProcess(Callable task) { + return startProcess(task, null); + } + + @Override + public AsyncResult startProcess(Callable task, AsyncCallback 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 endProcess(AsyncResult 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 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 launched successfully +21:47:08.519 [executor-5] INFO com.iluwatar.async.method.invocation.App - Deploying lunar rover +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 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) diff --git a/localization/fr/balking/README.md b/localization/fr/balking/README.md new file mode 100644 index 000000000..ea066a510 --- /dev/null +++ b/localization/fr/balking/README.md @@ -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) diff --git a/localization/fr/bridge/README.md b/localization/fr/bridge/README.md new file mode 100644 index 000000000..0d24a5687 --- /dev/null +++ b/localization/fr/bridge/README.md @@ -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)