A - Motif décoratif
A.1 - Cas d'utilisation du motif décorateur
Le modèle décorateur est utilisé pour étendre une fonctionnalité héritée sans modifier la classe héritée. Disons que nous avons une classe concrète qui implémente une interface. Et nous avons besoin d'étendre la fonctionnalité de la méthode existante, mais parce que la classe existante et ses méthodes sont déjà utilisées par d'autres classes, nous ne voulons pas faire de changement dans les classes existantes. Mais nous avons également besoin d'une fonctionnalité étendue sur une classe plus récente, alors comment résoudre ce problème ?
1- We can't change the existing legacy code
2- We want to extend the functionality
Nous utilisons donc le modèle des décorateurs, en enveloppant la classe existante dans les décorateurs.
B - Exemple de motif décorateur GoF de base
Ici, nous avons une interface simple et une implémentation/classe concrète. L'interface a une méthode simple, qui est getMessageOfTheDay
et il renvoie un String
. Supposons qu'il y ait beaucoup d'autres classes utilisant cette méthode. Donc si nous voulons faire un changement dans l'implémentation/classe concrète, cela affectera l'ancien code hérité. Nous voulons le modifier uniquement pour les nouvelles classes et nous utilisons donc le modèle du décorateur.
Voici un exemple trivial du motif Gang Of Four Decorator Design ;
B.1 - Greeter.java
public interface Greeter {
String getMessageOfTheDay();
}
B.2 - BasicGreeter.java
public class BasicGreeter implements Greeter {
@Override
public String getMessageOfTheDay() {
return "Welcome to my server";
}
}
B.3 - Classe décoratrice abstraite : GreeterDecorator.java
public abstract class GreeterDecorator implements Greeter {
protected Greeter greeter;
public GreeterDecorator(Greeter greeter) {
this.greeter = greeter;
}
public String getMessageOfTheDay() {
return greeter.getMessageOfTheDay();
}
}
B.4 - Classe de décorateur concret : StrangerDecorator.java
public class StrangerDecorator extends GreeterDecorator {
public StrangerDecorator(Greeter greeter) {
super(greeter);
}
@Override
public String getMessageOfTheDay() {
return "Hello Stranger " + super.getMessageOfTheDay();
}
}
B.5 - Code de démonstration : DecoratorDemo .java
public class DecoratorDemo {
public static void main(String[] args) {
Greeter greeter = new BasicGreeter();
String motd = greeter.getMessageOfTheDay();
System.out.println(motd);
Greeter newGreeter = new StrangerDecorator(greeter);
String newMotd = newGreeter.getMessageOfTheDay();
System.out.println(newMotd);
Greeter muchNewGreeter = new StrangerDecorator(new StrangerDecorator(greeter));
String newestMotd = muchNewGreeter.getMessageOfTheDay();
System.out.println(newestMotd);
}
}
Jetez un coup d'œil à ces exemples. La classe décorateur abstrait est nécessaire pour envelopper le contrat et l'implémentation d'origine. En utilisant le décorateur abstrait, vous pouvez créer de nouveaux décorateurs multiples mais dans cet exemple, BasicGreeter est enveloppé dans le décorateur abstrait et nous avons seulement créé une nouvelle classe de décorateur qui est StrangeGreeter . Veuillez noter que les classes de décorateurs peuvent être utilisées comme un train, nous pouvons envelopper un décorateur dans un autre décorateur ou le même. La fonctionnalité est extensible mais la classe originale est préservée sans aucune modification.
C - Démonstration de OutputStream
Jetons un coup d'œil à cet exemple. Nous voulons écrire une chaîne de caractères dans un fichier avec OutputStream. Voici le code de démonstration ;
C.1 - Exemple de démonstration de OutputStream pour écrire un fichier
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class FileWriterDemo {
public static void main(String[] args) throws IOException {
File file = new File("./normal.txt");
file.createNewFile();
OutputStream oStream = new FileOutputStream(file);
String content = "I love Commodore 64";
oStream.write(content.getBytes());
oStream.close();
}
}
C.2 - Sortie du décorateur JSON : normal.txt
Il y aura un nouveau fichier avec le nom "normal.txt" créé sous le dossier du projet et le contenu sera ;
I love Commodore 64
D - Démonstration du décorateur JSON OutputStream
Maintenant, je veux créer un format de wrapper JSON, qui est le suivant ;
{
data: <data here>
}
Ce que je veux, c'est écrire le contenu dans un simple champ. JSON format. Comment pouvons-nous atteindre cet objectif ? Il existe de nombreux moyens triviaux. Cependant, j'utiliserai le Patron de décorateur GoF en écrivant un JSONDecorator qui étend le OutputStream de Java ;
D.1 - Décorateur JSON pour OutputStream : JSONStream.java
public class JSONStream extends OutputStream {
protected OutputStream outputStream;
public JSONStream(OutputStream outputStream) {
this.outputStream = outputStream;
}
@Override
public void write(int b) throws IOException {
outputStream.write(b);
}
@Override
public void write(byte[] b) throws IOException {
String content = new String(b);
content = "{\r\n\tdata:\"" + content + "\"\r\n}";
outputStream.write(content.getBytes());
}
}
D.2 - Démonstration du décorateur JSON : JSONDecoratorDemo.java
public class JSONDecoratorDemo {
public static void main(String[] args) throws IOException {
File file = new File("./json.txt");
file.createNewFile();
OutputStream oStream = new FileOutputStream(file);
JSONStream js = new JSONStream(oStream);
String content = "I love Commodore 64";
js.write(content.getBytes());
js.close();
oStream.close();
}
}
D.3 - Sortie du décorateur JSON : json.txt
{
data:"I love Commodore 64"
}
En fait, OutputStream lui-même un motif de décorateur, c'est le décorateur abstrait et le décorateur concret ici est le JSONStream classe.