« Bonjour, Amigo ! Aujourd'hui, Ellie t'a parlé du modèle d'adaptateur. »

La plupart des classes liées aux flux d'E/S sont implémentées sous forme d'adaptateurs. Soit elles convertissent des interfaces équivalentes soit elles les connectent, en partant de la plus simple en allant vers la plus complexe.

« Est-ce qu'InputStreamReader et BufferedReader sont aussi des adaptateurs ? À tout le moins, ils sont très semblables aux adaptateurs dans la façon dont ils sont utilisés : Une fois qu'un objet est créé, il est passé au constructeur d'une autre classe. »

« Oui, InputStreamReader convertit l'interface InputStream en interface Reader. BufferedReader n'est pas un adaptateur sous sa forme la plus pure, car les créateurs de Java ont décidé de ne pas donner à ses méthodes leur propre interface séparée. Mais cela s'en rapproche beaucoup dans l'esprit. »

Au lieu d'écrire un gazillion de classes différentes, les créateurs de Java ont écrit deux douzaines d'adaptateurs et leur ont permis de se connecter les uns aux autres de toutes les façons qu'un programmeur pourrait vouloir.

Cette approche est très commode. Un programmeur peut toujours écrire sa classe et/ou son adaptateur, lui faire implémenter une interface standard et l'inclure dans la chaîne d'objets adaptateurs qu'il construit.

« Alors c'est comme ça que ça fonctionne. Au lieu de grandes classes complexes, nous créons des chaînes d'objets simples et d'adaptateurs. Et ensuite, il suffit de les créer et de les combiner dans l'ordre ! »

« Et tu implémentes tout ce qui manque. »

« Oui, je comprends. »

« Mais en réalité, je voulais te parler de Reader et Writer aujourd'hui. Ce sont deux classes abstraites qui sont très similaires aux classes InputStream et OutputStream. Mais contrairement à ces classes, ces deux-là travaillent avec des caractères. Elles lisent et écrivent des caractères. Elles sont très pratiques pour travailler avec des informations textuelles. Découvrons les méthodes qu'elles possèdent : »

Méthodes de Reader Ce que la méthode fait
int read(char[] cbuf);
« Cette méthode lit immédiatement plusieurs caractères dans le tampon (tableau de caractères), jusqu'à ce que le tampon soit plein ou jusqu'à ce que la source n'ait plus de caractères à lire. »
La méthode renvoie le nombre de caractères réellement lus (qui peut être inférieur à la longueur du tableau)
int read();
« Cette méthode lit un caractère et le renvoie. Le résultat est élargi en int à des fins cosmétiques. S'il n'y a plus de caractères disponibles, la méthode renvoie -1. »
boolean ready();
Cette méthode renvoie true s'il y a des caractères non lus pour les méthodes read
void close();
Cette méthode « ferme » le flux. Tu peux l'appeler quand tu as fini de travailler avec le flux.
L'objet effectue alors les opérations d'entretien nécessaires pour fermer le fichier, etc.
À ce stade, tu ne peux plus lire de données à partir du flux.

« Il se trouve que la méthode read(char [] cbuf) de Reader nous permet de lire des blocs entiers de caractères, plutôt qu'un seul caractère à la fois. Comme ça c'est plus rapide et pratique. »

« Exactement. Et maintenant, découvrons les méthodes de Writer : »

Méthode Ce que la méthode fait
void write(int c);
Cette méthode écrit un caractère. Le type int est réduit en char. La partie supplémentaire est tout simplement abandonnée.
void write(char[] cbuff);
Cette méthode écrit un tableau de caractères.
void write(String s);
Cette méthode écrit une chaîne. Elle est simplement convertie en un tableau de caractères, puis la deuxième méthode est appelée.
void flush();
Si le flux stocke en interne des données qui n'ont pas encore été écrites, la méthode force leur écriture.
void close();
Cette méthode « ferme » le flux. Tu peux l'appeler quand tu as fini de travailler avec le flux.
L'objet effectue alors les opérations d'entretien nécessaires pour fermer le fichier, etc. Tu ne peux plus écrire des données sur le flux, et la méthode flush est appelée automatiquement.

Il est important de comprendre que Reader et Writer sont des classes abstraites. Elles ne font rien et ne contiennent pratiquement pas de code. Toutes leurs méthodes devront être implémentées dans les classes qui en héritent. Leur travail est de normaliser la façon dont les classes interagissent. Les développeurs n'ont pas besoin d'inventer leurs propres normes pour interagir entre eux. Il est beaucoup plus pratique pour tout le monde de partager quelques normes de base. Cela permet à des classes écrites par différents programmeurs d'interagir facilement non seulement avec les classes écrites par les créateurs de Java, mais aussi avec celles écrites par d'autres programmeurs.

Les normes sont puissantes.

« Bien dit. Soutenir des normes communes est bénéfique pour tout le monde. »