JavaRush /Blog Java /Random-ES /Adaptador de patrón de diseño

Adaptador de patrón de diseño

Publicado en el grupo Random-ES
¡Hola! Hoy tocaremos un tema nuevo e importante: los patrones o, en otras palabras, los patrones de diseño . ¿Qué son los patrones? Creo que conoces la expresión "no reinventar la rueda". En programación, como en muchas otras áreas, existen una gran cantidad de situaciones típicas. Para cada uno de ellos, en el proceso de desarrollo de la programación, se crearon soluciones de trabajo listas para usar. Estos son patrones de diseño. En términos relativos, un patrón es un ejemplo determinado que ofrece una solución a una situación como: "si su programa necesita hacer algo, cuál es la mejor manera de hacerlo". Hay muchos patrones, a ellos está dedicado un excelente libro "Estudiar patrones de diseño", que definitivamente deberías leer. Patrón de diseño "Adaptador" - 2Para decirlo lo más brevemente posible, un patrón consiste en un problema común y su solución, que ya puede considerarse una especie de estándar. En la conferencia de hoy nos familiarizaremos con uno de estos patrones llamado "Adaptador". Su nombre lo dice todo y te has encontrado con adaptadores en la vida real más de una vez. Uno de los adaptadores más comunes son los lectores de tarjetas, que están equipados con muchas computadoras y portátiles. Patrón de diseño del adaptador - 3Imaginemos que tenemos una especie de tarjeta de memoria. ¿Cuál es el problema? El caso es que ella no sabe interactuar con una computadora. No tienen una interfaz común. La computadora tiene un conector USB, pero no puede insertar una tarjeta de memoria en él. La tarjeta no se puede insertar en la computadora, por lo que no podremos guardar nuestras fotos, videos y otros datos. El lector de tarjetas es un adaptador que soluciona este problema. Después de todo, ¡tiene un cable USB! A diferencia de la propia tarjeta, el lector de tarjetas se puede insertar en una computadora. Tienen una interfaz común con la computadora: USB. Veamos cómo quedaría con un ejemplo:
public interface USB {

   void connectWithUsbCable();
}
Esta es nuestra interfaz USB siendo el único método insertar el cable USB:
public class MemoryCard {

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

   public void copyData() {
       System.out.println("Данные скопированы на компьютер!");
   }
}
Esta es nuestra clase que implementa el mapa de memoria. Ya tiene 2 métodos que necesitamos, pero aquí está el problema: no implementa la interfaz USB. La tarjeta no se puede insertar en la ranura 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();
   }
}
¡Y aquí está nuestro adaptador! ¿Qué hace la claseCardReader y por qué es un adaptador? Es sencillo. La clase que se está adaptando (mapa de memoria) se convierte en uno de los campos del adaptador. Esto es lógico, porque en la vida real también insertamos una tarjeta dentro del lector de tarjetas, y también pasa a formar parte de él. A diferencia de una tarjeta de memoria, el adaptador tiene una interfaz común con la computadora. Tiene un cable USB, lo que significa que se puede conectar a otros dispositivos mediante USB. Por lo tanto, en el programa, nuestra clase CardReaderimplementa la interfaz USB. ¿Pero qué sucede dentro de este método? ¡Y sucede exactamente lo que necesitamos! El adaptador delega el trabajo a nuestra tarjeta de memoria. Después de todo, el adaptador en sí no hace nada; el lector de tarjetas no tiene ninguna funcionalidad independiente. ¡Su trabajo es sólo vincular la computadora y la tarjeta de memoria para que la tarjeta pueda hacer su trabajo y copiar archivos! Nuestro adaptador le permite hacer esto proporcionando su propia interfaz (método connectWithUsbCable()) para las "necesidades" de la tarjeta de memoria. Creemos algún tipo de programa cliente que simule a una persona que quiere copiar datos de una tarjeta de memoria:
public class Main {

   public static void main(String[] args) {

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

   }
}
¿Qué obtuvimos como resultado? Salida de consola:
Карта памяти успешно вставлена!
Данные скопированы на компьютер!
¡Genial, nuestra tarea se ha completado con éxito! Aquí hay algunos enlaces adicionales con información sobre el patrón Adaptador:

Clases de resúmenes lector y escritor.

Ahora volvemos a nuestro pasatiempo favorito: aprenderemos un par de clases nuevas para trabajar con entrada y salida :) ¿Cuántas de ellas ya hemos aprendido, me pregunto? Hoy hablaremos de clases Readery Writer. ¿Por qué sobre ellos? Porque esto estará relacionado con nuestra sección anterior: adaptadores. Veámoslos con más detalle. Empecemos con Reader'a. ReaderEs una clase abstracta, por lo que no podremos crear sus objetos explícitamente. Pero, de hecho, ¡ya lo conoces! Después de todo, las clases que conoces bien BufferedReaderson InputStreamReadersus herederas :)
public class BufferedReader extends Reader {}

public class InputStreamReader extends Reader {}
Entonces, una clase InputStreamReaderes un adaptador clásico . Como probablemente recuerdes, podemos pasar un objeto a su constructor InputStream. La mayoría de las veces usamos una variable para esto System.in:
public static void main(String[] args) {

   InputStreamReader inputStreamReader = new InputStreamReader(System.in);
}
Qué hace InputStreamReader? Como cualquier adaptador, convierte una interfaz en otra. En este caso, la interfaz InputStream'a a la interfaz Reader'a. Inicialmente teníamos una clase InputStream. Funciona bien, pero sólo puede leer bytes individuales. Además, tenemos una clase abstracta Reader. Tiene una funcionalidad excelente que realmente necesitamos: ¡puede leer caracteres! Por supuesto, realmente necesitamos esta oportunidad. Pero aquí nos enfrentamos a un problema clásico que suelen resolver los adaptadores: la incompatibilidad de interfaces. ¿Cómo se manifiesta? Veamos directamente la documentación de Oracle. Aquí están los métodos de clase InputStream. Patrón de diseño "Adaptador" - 4Un conjunto de métodos es una interfaz. Como puede ver, read()esta clase tiene un método (incluso en varias versiones), pero solo puede leer bytes: bytes individuales o varios bytes usando un búfer. Esta opción no nos conviene: queremos leer caracteres. La funcionalidad que necesitamos ya está implementada en la clase abstractaReader . Esto también se puede ver en la documentación. Patrón de diseño del adaptador - 5Sin embargo, las interfaces InputStream'a' y 'a' son incompatibles. ReaderComo puede ver, en todas las implementaciones de métodos, read()tanto los parámetros pasados ​​como los valores de retorno difieren. ¡ Y aquí es donde lo necesitamos InputStreamReader! Actuará como Adaptador entre nuestras clases. Como en el ejemplo del lector de tarjetas que vimos anteriormente, pasamos el objeto de la clase "adaptada" "internamente", es decir, al constructor de la clase adaptadora. En el ejemplo anterior, pasamos un objeto MemoryCarddentro CardReader. ¡ Ahora pasamos el objeto InputStreamal constructor InputStreamReader! Como cualidad InputStreamutilizamos la ya familiar variable System.in:
public static void main(String[] args) {

   InputStreamReader inputStreamReader = new InputStreamReader(System.in);
}
Y efectivamente: mirando la documentación InputStreamReaderveremos que la “adaptación” fue exitosa :) Ahora tenemos a nuestra disposición métodos que nos permiten leer caracteres. Patrón de diseño del adaptador - 6Y aunque inicialmente nuestro objeto System.in(un hilo vinculado al teclado) no lo permitía, al crear el patrón Adaptador , los creadores del lenguaje resolvieron este problema. La clase abstracta Reader, como la mayoría de las clases de E/S, tiene un hermano gemelo: Writer. Tiene la misma gran ventaja Reader: proporciona una interfaz cómoda para trabajar con símbolos. Con los flujos de salida, el problema y su solución tienen el mismo aspecto que en el caso de los flujos de entrada. Hay una clase OutputStreamque sólo puede escribir bytes; Hay una clase abstracta Writerque puede trabajar con símbolos y hay dos interfaces incompatibles. Este problema se resuelve nuevamente con éxito mediante el patrón Adaptador. Usando una clase, OutputStreamWriterpodemos "adaptar" fácilmente dos interfaces de clase Writerentre OutputStreamsí. Y, habiendo recibido un flujo de bytes OutputStreamen el constructor, con la ayuda OutputStreamWriterpodemos, sin embargo, escribir caracteres, ¡no bytes!
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();
   }
}
Escribimos un carácter con el código 32144 - 綐 en nuestro archivo, eliminando así la necesidad de trabajar con bytes :) Eso es todo por hoy, ¡nos vemos en las próximas conferencias! :)
Comentarios
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION