JavaRush /Blog Java /Random-FR /Adaptateur de modèle de conception

Adaptateur de modèle de conception

Publié dans le groupe Random-FR
Bonjour! Aujourd'hui, nous aborderons un nouveau sujet important : les modèles, ou en d'autres termes, les modèles de conception . Que sont les modèles ? Je pense que vous connaissez l’expression « ne réinventez pas la roue ». En programmation, comme dans bien d’autres domaines, il existe un grand nombre de situations typiques. Pour chacun d'eux, au cours du processus de développement de la programmation, des solutions de travail prêtes à l'emploi ont été créées. Ce sont des modèles de conception. Relativement parlant, un modèle est un exemple donné qui offre une solution à une situation telle que : « si votre programme doit faire quelque chose, quelle est la meilleure façon de le faire ». Il existe de nombreux modèles, un excellent livre « Studying Design Patterns » leur est dédié, que vous devez absolument lire. Modèle de conception "Adaptateur" - 2Pour le dire le plus brièvement possible, un modèle consiste en un problème commun et sa solution, qui peut déjà être considérée comme une sorte de standard. Dans la conférence d'aujourd'hui, nous allons nous familiariser avec l'un de ces modèles appelé « Adaptateur ». Son nom est révélateur et vous avez rencontré plus d'une fois des adaptateurs dans la vraie vie. L'un des adaptateurs les plus courants est celui des lecteurs de cartes, qui équipent de nombreux ordinateurs et ordinateurs portables. Modèle de conception d'adaptateur - 3Imaginez que nous ayons une sorte de carte mémoire. Quel est le problème? Le fait est qu’elle ne sait pas interagir avec un ordinateur. Ils n'ont pas d'interface commune. L'ordinateur dispose d'un connecteur USB, mais vous ne pouvez pas y insérer de carte mémoire. La carte ne peut pas être insérée dans l'ordinateur, ce qui nous empêche de sauvegarder nos photos, vidéos et autres données. Le lecteur de carte est un adaptateur qui résout ce problème. Après tout, il a un câble USB ! Contrairement à la carte elle-même, le lecteur de carte peut être inséré dans un ordinateur. Ils ont une interface commune avec l'ordinateur - USB. Voyons à quoi cela ressemblerait avec un exemple :
public interface USB {

   void connectWithUsbCable();
}
Il s'agit de notre interface USB, la seule méthode étant d'insérer le câble USB :
public class MemoryCard {

   public void insert() {
       System.out.println("Карта памяти успешно вставлена!");
   }

   public void copyData() {
       System.out.println("Данные скопированы на компьютер!");
   }
}
C'est notre classe qui implémente la carte mémoire. Il dispose déjà de 2 méthodes dont nous avons besoin, mais voici le problème : il n’implémente pas l’interface USB. La carte ne peut pas être insérée dans le port USB.
public class CardReader implements USB {

   private MemoryCard memoryCard;

   public CardReader(MemoryCard memoryCard) {
       this.memoryCard = memoryCard;
   }

   @Override
   public void connectWithUsbCable() {
       this.memoryCard.insert();
       this.memoryCard.copyData();
   }
}
Et voici notre adaptateur ! Que fait la classeCardReader et pourquoi est-elle un adaptateur ? C'est simple. La classe adaptée (carte mémoire) devient l'un des champs de l'adaptateur. C'est logique, car dans la vraie vie, nous insérons également une carte à l'intérieur du lecteur de carte, et elle en fait également partie. Contrairement à une carte mémoire, l'adaptateur possède une interface commune avec l'ordinateur. Il dispose d'un câble USB, ce qui signifie qu'il peut se connecter à d'autres appareils via USB. Par conséquent, dans le programme, notre classe CardReaderimplémente l'interface USB. Mais que se passe-t-il dans cette méthode ? Et il arrive exactement ce dont nous avons besoin ! L'adaptateur délègue le travail à notre carte mémoire. Après tout, l'adaptateur lui-même ne fait rien, le lecteur de carte n'a aucune fonctionnalité indépendante. Son rôle consiste uniquement à relier l'ordinateur et la carte mémoire pour que la carte puisse faire son travail et copier des fichiers ! Notre adaptateur lui permet de le faire en fournissant sa propre interface (méthode connectWithUsbCable()) pour les « besoins » de la carte mémoire. Créons une sorte de programme client qui simulera une personne qui souhaite copier des données depuis une carte mémoire :
public class Main {

   public static void main(String[] args) {

       USB cardReader = new CardReader(new MemoryCard());
       cardReader.connectWithUsbCable();

   }
}
Qu’avons-nous obtenu en conséquence ? Sortie de la console :
Карта памяти успешно вставлена!
Данные скопированы на компьютер!
Génial, notre tâche a été accomplie avec succès ! Voici quelques liens supplémentaires contenant des informations sur le modèle d'adaptateur :

Cours abstraits Lecteur et Écrivain

Revenons maintenant à notre passe-temps favori : nous allons apprendre quelques nouveaux cours pour travailler avec les entrées et les sorties :) Combien d'entre eux avons-nous déjà appris, je me demande ? Aujourd'hui, nous parlerons des cours Readeret Writer. Pourquoi à leur sujet ? Parce que cela sera lié à notre section précédente – les adaptateurs. Examinons-les plus en détail. Commençons par Reader'a. Readerest une classe abstraite, nous ne pourrons donc pas créer explicitement ses objets. Mais en fait, vous le connaissez déjà ! Après tout, les classes que vous connaissez bien BufferedReadersont InputStreamReaderses héritières :)
public class BufferedReader extends Reader {}

public class InputStreamReader extends Reader {}
Une classeInputStreamReader est donc un adaptateur classique . Comme vous vous en souvenez probablement, nous pouvons passer un objet à son constructeur InputStream. Le plus souvent on utilise pour cela une variable System.in:
public static void main(String[] args) {

   InputStreamReader inputStreamReader = new InputStreamReader(System.in);
}
Qu'est ce que ça fait InputStreamReader? Comme tout adaptateur, il convertit une interface en une autre. Dans ce cas, l'interface InputStream'a vers l'interface Reader'a. Au début, nous avions un cours InputStream. Cela fonctionne bien, mais il ne peut lire que des octets individuels. De plus, nous avons une classe abstraite Reader. Il possède une excellente fonctionnalité dont nous avons vraiment besoin : il peut lire des caractères ! Bien entendu, nous avons vraiment besoin de cette opportunité. Mais nous sommes ici confrontés à un problème classique que les adaptateurs résolvent généralement : l'incompatibilité des interfaces. Comment se manifeste-t-il ? Regardons directement la documentation Oracle. Voici les méthodes de classe InputStream. Modèle de conception "Adaptateur" - 4Un ensemble de méthodes est une interface. Comme vous pouvez le constater, read()cette classe possède une méthode (même en plusieurs versions), mais elle ne peut lire que des octets : soit des octets individuels, soit plusieurs octets à l'aide d'un buffer. Cette option ne nous convient pas - nous voulons lire des caractères. La fonctionnalité dont nous avons besoin est déjà implémentée dans la classe abstraiteReader . Cela peut également être vu dans la documentation. Modèle de conception d'adaptateur - 5Cependant, les interfaces InputStream« a » et « a » sont incompatibles ! ReaderComme vous pouvez le voir, dans toutes les implémentations de méthodes, read()les paramètres transmis et les valeurs de retour diffèrent. Et c'est là qu'on en a besoin InputStreamReader! Il agira comme adaptateur entre nos cours. Comme dans l'exemple du lecteur de carte que nous avons examiné ci-dessus, nous transmettons l'objet de la classe « adaptée » « en interne », c'est-à-dire au constructeur de la classe adaptateur. Dans l'exemple précédent, nous avons passé un objet MemoryCardà l'intérieur de CardReader. Maintenant, nous passons l'objet InputStreamau constructeur InputStreamReader! Comme qualité InputStreamnous utilisons la variable déjà familière System.in:
public static void main(String[] args) {

   InputStreamReader inputStreamReader = new InputStreamReader(System.in);
}
Et en effet : en regardant la documentation InputStreamReadernous verrons que « l'adaptation » a réussi :) Nous avons désormais à notre disposition des méthodes qui nous permettent de lire des caractères. Modèle de conception d'adaptateur - 6Et bien qu'au départ notre objet System.in(un thread lié au clavier) ne le permettait pas, en créant le modèle Adapter , les créateurs du langage ont résolu ce problème. La classe abstraite Reader, comme la plupart des classes d'E/S, a un frère jumeau - Writer. Il présente le même gros avantage Reader: il fournit une interface pratique pour travailler avec des symboles. Avec les flux de sortie, le problème et sa solution sont les mêmes que dans le cas des flux d'entrée. Il existe une classe OutputStreamqui ne peut écrire que des octets ; Il existe une classe abstraite Writerqui peut fonctionner avec des symboles et deux interfaces incompatibles. Ce problème est à nouveau résolu avec succès par le modèle Adaptateur. En utilisant une classe, OutputStreamWriternous pouvons facilement « adapter » deux interfaces de classe l’une Writerà OutputStreaml’autre. Et, après avoir reçu un flux d'octets OutputStreamdans le constructeur, avec l'aide OutputStreamWriternous pouvons cependant écrire des caractères, pas des octets !
import java.io.*;

public class Main {

   public static void main(String[] args) throws IOException {

       OutputStreamWriter streamWriter = new OutputStreamWriter(new FileOutputStream("C:\\Users\\Username\\Desktop\\test.txt"));
       streamWriter.write(32144);
       streamWriter.close();
   }
}
Nous avons écrit un caractère avec le code 32144 - 綐 dans notre fichier, éliminant ainsi le besoin de travailler avec des octets :) C'est tout pour aujourd'hui, rendez-vous dans les prochaines conférences ! :)
Commentaires
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION