CodeGym /Blogue Java /Random-PT /Padrão de design do adaptador
John Squirrels
Nível 41
San Francisco

Padrão de design do adaptador

Publicado no grupo Random-PT
Oi! Hoje abordaremos um novo tópico importante: padrões de projeto . Quais são esses padrões? Acho que você deve conhecer a expressão “ não reinvente a roda ”. Na programação, como em muitas outras áreas, existe um grande número de situações comuns. À medida que o desenvolvimento de software evoluiu, foram criadas soluções prontas que funcionam para cada um deles. Essas soluções são chamadas de padrões de projeto. Por convenção, um padrão é uma solução formulada assim: "se você precisa fazer X em seu programa, então esta é a melhor maneira de fazê-lo". Existem muitos padrões. O excelente livro "Head First Design Patterns", com o qual você definitivamente deveria se familiarizar, é dedicado a eles. Padrão de design do adaptador - 2Em poucas palavras, um padrão consiste em um problema comum e uma solução correspondente que pode ser considerada uma espécie de padrão. Na lição de hoje, conheceremos um desses padrões: Adaptador. Seu nome diz tudo, e você já encontrou adaptadores muitas vezes na vida real. Alguns dos adaptadores mais comuns são os leitores de cartão que muitos computadores e laptops possuem. Padrão de design do adaptador - 3Suponha que temos algum tipo de cartão de memória. Então qual é o problema? Não sabe interagir com o computador. Eles não compartilham uma interface comum. O computador tem uma porta USB, mas não podemos inserir o cartão de memória nela. O cartão não pode ser conectado ao computador, então não podemos salvar nossas fotos, vídeos e outros dados. Um leitor de cartão é um adaptador que resolve esse problema. Afinal, ele tem um cabo USB! Ao contrário do próprio cartão, o leitor de cartão pode ser conectado ao computador. Eles compartilham uma interface comum com o computador: USB. Vamos ver como isso fica na prática:

public interface USB { 

   void connectWithUsbCable(); 
}
Esta é a nossa interface USB com apenas um método de conexão via USB.

public class MemoryCard { 

   public void insert() { 
       System.out.println("Memory card successfully inserted!"); 
   } 

   public void copyData() { 
       System.out.println("The data has been copied to the computer!"); 
   } 
}
Esta é a nossa classe representando o cartão de memória. Ele já tem os 2 métodos que precisamos, mas aqui está o problema: ele não implementa a interface USB. O cartão não pode ser inserido na porta 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(); 
   } 
}
E aqui está o nosso adaptador! O que faz oCardReaderclasse faz e o que exatamente o torna um adaptador? É tudo simples. A classe que está sendo adaptada (MemoryCard) passa a ser um dos campos do adaptador. Isso faz sentido. Quando colocamos um cartão de memória dentro de um leitor de cartões na vida real, ele também se torna parte dele. Ao contrário do cartão de memória, o adaptador compartilha uma interface com o computador. Possui cabo USB, ou seja, pode ser conectado a outros dispositivos via USB. É por isso que nossa classe CardReader implementa a interface USB. Mas o que exatamente acontece dentro desse método? Exatamente o que precisamos que aconteça! O adaptador delega o trabalho ao nosso cartão de memória. De fato, o adaptador não faz nada sozinho. Um leitor de cartão não possui nenhuma funcionalidade independente. Sua função é apenas conectar o computador e o cartão de memória para permitir que o cartão faça seu trabalho — copiar arquivos!connectWithUsbCable()método) para atender às "necessidades" do cartão de memória. Vamos criar um programa cliente que irá simular uma pessoa que deseja copiar dados de um cartão de memória:

public class Main { 

   public static void main(String[] args) { 

       USB cardReader = new CardReader(new MemoryCard()); 
       cardReader.connectWithUsbCable(); 
   } 
}
Então, o que conseguimos? Saída do console:

Memory card successfully inserted! 
The data has been copied to the computer!
Excelente. Alcançamos nosso objetivo! Aqui está um link para um vídeo com informações sobre o padrão Adapter:

Classes abstratas Reader e Writer

Agora retornaremos à nossa atividade favorita: aprender sobre algumas novas classes para trabalhar com entrada e saída :) Gostaria de saber quantas já aprendemos. Hoje falaremos sobre as classes Reader e Writer. Por que especificamente essas aulas? Porque eles estão relacionados à nossa seção anterior sobre adaptadores. Vamos examiná-los com mais detalhes. Começaremos com  Reader. Readeré uma classe abstrata, portanto não poderemos criar objetos explicitamente.   Mas você já está familiarizado com isso! Afinal, você conhece bem as classes BufferedReadere InputStreamReader, que são suas descendentes :)

public class BufferedReader extends Reader { 
… 
} 

public class InputStreamReader extends Reader { 
… 
}
A InputStreamReaderclasse é um adaptador clássico. Como você provavelmente se lembra, podemos passar um InputStreamobjeto para seu construtor. Para fazer isso, geralmente usamos a System.invariável:

public static void main(String[] args) { 

   InputStreamReader inputStreamReader = new InputStreamReader(System.in); 
}
Mas o que InputStreamReaderfaz? Como todo adaptador, ele converte uma interface em outra.  Nesse caso, a InputStreaminterface para a Readerinterface. Inicialmente, temos a InputStreamclasse. Funciona bem, mas você só pode usá-lo para ler bytes individuais. Além disso, temos uma Readerclasse abstrata. Ele tem algumas funcionalidades muito úteis — ele sabe como ler caracteres! Nós certamente precisamos dessa habilidade. Mas aqui enfrentamos o problema clássico geralmente resolvido por adaptadores — interfaces incompatíveis. O que isso significa? Vamos dar uma olhada na documentação do Oracle. Aqui estão os métodos da InputStreamclasse. Padrão de design do adaptador - 4Um conjunto de métodos é exatamente o que é uma interface. Como você pode ver, esta classe tem umread()método (algumas variantes, na verdade), mas só pode ler bytes: ou bytes individuais ou vários bytes usando um buffer. Mas esta opção não nos convém - queremos ler caracteres. Precisamos da funcionalidade que já está implementada na Readerclasse abstrata . Também podemos ver isso na documentação. Padrão de design do adaptador - 5No entanto, as interfaces InputStreame  Readersão incompatíveis! Como você pode ver, cada implementação do read()método tem diferentes parâmetros e valores de retorno. E é aqui que precisamos InputStreamReader! Ele atuará como um adaptador entre nossas classes. Como no exemplo do leitor de cartões, que consideramos acima, colocamos uma instância da classe que está sendo adaptada "dentro" da classe adaptadora, ou seja, passamos uma para o seu construtor. No exemplo anterior, colocamos um MemoryCardobjeto dentro de CardReader. Agora estamos passando um InputStream objeto para o InputStreamReaderconstrutor! Usamos nossa System.invariável familiar como InputStream:

public static void main(String[] args) { 

   InputStreamReader inputStreamReader = new InputStreamReader(System.in); 
}
E, de fato, olhando a documentação do InputStreamReader, podemos ver que a adaptação foi bem-sucedida :) Agora temos métodos para ler caracteres à nossa disposição. Padrão de design do adaptador - 6E embora nosso System.inobjeto (o fluxo vinculado ao teclado) inicialmente não permitisse isso, os criadores da linguagem resolveram esse problema implementando o padrão do adaptador. A Readerclasse abstrata, como a maioria das classes de E/S, tem um irmão gêmeo —  Writer. Tem a mesma grande vantagem de  Reader — fornece uma interface conveniente para trabalhar com personagens. Com fluxos de saída, o problema e sua solução têm a mesma aparência dos fluxos de entrada. Existe uma OutputStreamclasse que só pode escrever bytes, existe umaWriterclasse abstrata que sabe como trabalhar com personagens e existem duas interfaces incompatíveis. Esse problema é novamente resolvido pelo padrão do adaptador. Usamos a OutputStreamWriterclasse para adaptar facilmente as duas interfaces das classes Writer e  OutputStream entre si. Depois de passar um OutputStreamfluxo de bytes para o construtor, podemos usar an OutputStreamWriterpara escrever caracteres em vez de 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();
   } 
}
Escrevemos o caractere com o código 32144 (綐) em nosso arquivo, eliminando a necessidade de trabalhar com bytes :) Por hoje é só. Nos vemos nas próximas aulas! :)
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION