Nous avons déjà passé en revue l'utilisation d'un objet singleton, mais vous ne réalisez peut-être pas encore que cette stratégie est un modèle de conception, et l'un des plus utilisés.
En fait, ces modèles sont nombreux et peuvent être classés en fonction de leur objectif spécifique.
Classement des modèles
Type de motif | Application |
---|---|
Créationnel | Un type qui résout le problème de création d'objet |
De construction | Des modèles qui nous permettent de construire une hiérarchie de classes correcte et extensible dans notre architecture |
Comportemental | Ce groupe de modèles facilite une interaction sûre et pratique entre les objets d'un programme. |
Typiquement, un modèle est caractérisé par le problème qu'il résout. Jetons un coup d'œil à quelques modèles que nous rencontrons le plus souvent lorsque nous travaillons avec Java :
Modèle | But |
---|---|
Singleton | Nous connaissons déjà ce modèle — nous l'utilisons pour créer et accéder à une classe qui ne peut pas avoir plus d'une instance. |
Itérateur | Nous connaissons également celui-ci. Nous savons que ce modèle nous permet de parcourir un objet de collection sans révéler sa représentation interne. Il est utilisé avec les collections. |
Adaptateur | Ce modèle connecte des objets incompatibles afin qu'ils puissent fonctionner ensemble. Je pense que le nom du modèle d'adaptateur vous aide à imaginer exactement ce qu'il fait. Voici un exemple simple tiré de la vie réelle : un adaptateur USB pour une prise murale. |
Méthode de modèle | Un modèle de programmation comportementale qui résout le problème d'intégration et vous permet de modifier les étapes algorithmiques sans modifier la structure d'un algorithme. Imaginons que nous ayons un algorithme d'assemblage de voiture sous la forme d'une séquence d'étapes d'assemblage : Châssis -> Carrosserie -> Moteur -> Intérieur de la cabine Si on met un châssis renforcé, un moteur plus puissant, ou un intérieur avec un éclairage supplémentaire, on n'a pas à changer d'algorithme, et la séquence abstraite reste la même. |
Décorateur | Ce modèle crée des wrappers pour les objets afin de leur donner des fonctionnalités utiles. Nous l'examinerons dans le cadre de cet article. |
Dans Java.io, les classes suivantes implémentent des modèles :
Modèle | Où il est utilisé dans java.io |
---|---|
Adaptateur |
|
Méthode de modèle | |
Décorateur |
Motif décorateur
Imaginons que nous décrivons un modèle pour une conception de maison.
En général, l'approche ressemble à ceci:
Au départ, nous avons le choix entre plusieurs types de maisons. La configuration minimale est d'un étage avec un toit. Ensuite, nous utilisons toutes sortes de décorateurs pour modifier des paramètres supplémentaires, ce qui affecte naturellement le prix de la maison.
Nous créons une classe House abstraite :
public abstract class House {
String info;
public String getInfo() {
return info;
}
public abstract int getPrice();
}
Ici, nous avons 2 méthodes :
- getInfo() renvoie des informations sur le nom et les caractéristiques de notre maison ;
- getPrice() renvoie le prix de la configuration actuelle de la maison.
Nous avons également des implémentations standard de maison - brique et bois :
public class BrickHouse extends House {
public BrickHouse() {
info = "Brick House";
}
@Override
public int getPrice() {
return 20_000;
}
}
public class WoodenHouse extends House {
public WoodenHouse() {
info = "Wooden House";
}
@Override
public int getPrice() {
return 25_000;
}
}
Les deux classes héritent de la classe House et remplacent sa méthode de prix, en définissant un prix personnalisé pour une maison standard. Nous définissons le nom dans le constructeur.
Ensuite, nous devons écrire des classes de décorateur. Ces classes hériteront également de la classe House . Pour ce faire, nous créons une classe de décorateur abstraite.
C'est là que nous allons mettre une logique supplémentaire pour changer un objet. Initialement, il n'y aura pas de logique supplémentaire et la classe abstraite sera vide.
abstract class HouseDecorator extends House {
}
Ensuite, nous créons des implémentations de décorateur. Nous allons créer plusieurs classes qui nous permettront d'ajouter des fonctionnalités supplémentaires à la maison :
public class SecondFloor extends HouseDecorator {
House house;
public SecondFloor(House house) {
this.house = house;
}
@Override
public int getPrice() {
return house.getPrice() + 20_000;
}
@Override
public String getInfo() {
return house.getInfo() + " + second floor";
}
}
Un décorateur qui ajoute un deuxième étage à notre maison |
Le constructeur décorateur accepte une maison que nous allons « décorer », c'est-à-dire apporter des modifications. Et nous remplaçons les méthodes getPrice() et getInfo() , renvoyant des informations sur la nouvelle maison mise à jour en fonction de l'ancienne.
public class Garage extends HouseDecorator {
House house;
public Garage(House house) {
this.house = house;
}
@Override
public int getPrice() {
return house.getPrice() + 5_000;
}
@Override
public String getInfo() {
return house.getInfo() + " + garage";
}
}
Un décorateur qui ajoute un garage à notre maison |
Maintenant, nous pouvons mettre à jour notre maison avec des décorateurs. Pour ce faire, nous devons créer une maison :
House brickHouse = new BrickHouse();
Ensuite, nous fixons notrelogervariable égale à un nouveau décorateur, passant dans notre maison :
brickHouse = new SecondFloor(brickHouse);
Notrelogervariable est maintenant une maison avec un deuxième étage.
Examinons des cas d'utilisation impliquant des décorateurs :
Exemple de code | Sortir |
---|---|
|
Une maison en brique 20000 |
|
Maison en brique + deuxième étage 40000 |
|
Maison en brique + deuxième étage + garage 45000 |
|
Maison en bois + garage + deuxième étage 50000 |
|
Maison en bois 25000 Maison en bois + garage 30000 |
Cet exemple illustre l'avantage d'améliorer un objet avec un décorateur. Nous n'avons donc pas modifié lemaison en boisl'objet lui-même, mais a plutôt créé un nouvel objet basé sur l'ancien. Ici, nous pouvons voir que les avantages s'accompagnent d'inconvénients : nous créons à chaque fois un nouvel objet en mémoire, ce qui augmente la consommation de mémoire.
Regardez ce diagramme UML de notre programme :

Un décorateur a une implémentation super simple et modifie dynamiquement les objets, les mettant à niveau. Les décorateurs peuvent être reconnus par leurs constructeurs, qui prennent comme paramètres des objets du même type abstrait ou de la même interface que la classe actuelle. En Java, ce modèle est largement utilisé dans les classes d'E/S.
Par exemple, comme nous l'avons déjà noté, toutes les sous-classes de java.io.InputStream , OutputStream , Reader et Writer ont un constructeur qui accepte les objets des mêmes classes.
GO TO FULL VERSION