JavaRush /Blogue Java /Random-PT /Interfaces em Java

Interfaces em Java

Publicado no grupo Random-PT
Olá! Hoje falaremos sobre um conceito importante em Java: interfaces. A palavra provavelmente é familiar para você. Por exemplo, a maioria dos programas de computador e jogos possuem interfaces. Num sentido amplo, uma interface é uma espécie de “controle remoto” que conecta duas partes interagindo entre si. Um exemplo simples de interface da vida cotidiana é o controle remoto de uma TV. Ele conecta dois objetos, uma pessoa e uma TV, e realiza diversas tarefas: aumentar ou diminuir o volume, mudar de canal, ligar ou desligar a TV. Um lado (a pessoa) precisa acessar a interface (pressionar o botão do controle remoto) para que o outro lado execute a ação. Por exemplo, para a TV mudar de canal para o próximo. Nesse caso, o usuário não precisa conhecer o dispositivo da TV e como é implementado o processo de mudança de canal dentro dela. Por que precisamos de interfaces em Java - 1Tudo o que o usuário tem acesso é a interface . A principal tarefa é obter o resultado desejado. O que isso tem a ver com programação e Java? Direto :) Criar uma interface é muito semelhante a criar uma classe normal, só que em vez da palavra classespecificamos a palavra interface. Vamos dar uma olhada na interface Java mais simples e descobrir como ela funciona e para que é necessária:
public interface Swimmable  {

     public void swim();
}
Criamos uma interface Swimmableque pode nadar . É algo parecido com o nosso controle remoto, que possui um “botão”: o método swim() é “nadar”. Como podemos usar esse “ controle remoto ”? Para este propósito, o método, ou seja, o botão do nosso controle remoto precisa ser implementado. Para utilizar uma interface, seus métodos devem ser implementados por algumas classes do nosso programa. Vamos criar uma classe cujos objetos se encaixem na descrição “sabe nadar”. Por exemplo, a classe pato é adequada Duck:
public class Duck implements Swimmable {

    public void swim() {
        System.out.println("Duck, swim!");
    }

    public static void main(String[] args) {

        Duck duck = new Duck();
        duck.swim();
    }
}
O que vemos aqui? Uma classe Duckestá associada a uma interface Swimmableusando a palavra-chave implements. Se você se lembra, usamos um mecanismo semelhante para conectar duas classes em herança, só que havia a palavra “ estende ”. “ public class Duck implements Swimmable” pode ser traduzido literalmente para maior clareza: “uma classe pública Duckimplementa a interface Swimmable.” Isto significa que uma classe associada a uma interface deve implementar todos os seus métodos. Observação: em nossa classe, Duckassim como na interface , Swimmableexiste um método swim()e dentro dele existe algum tipo de lógica. Este é um requisito obrigatório. Se apenas escrevêssemos “ public class Duck implements Swimmable” e não criássemos um método swim()na classe Duck, o compilador nos daria um erro: Duck não é abstrato e não substitui o método abstrato swim() em Swimmable Por que isso acontece? Se explicarmos o erro usando o exemplo de uma TV, descobrimos que estamos dando a uma pessoa um controle remoto com botão “mudar de canal” de uma TV que não sabe mudar de canal. Neste ponto, pressione o botão o quanto quiser, nada funcionará. O próprio controle remoto não muda de canal: apenas dá um sinal para a TV, dentro da qual é implementado um complexo processo de mudança de canal. O mesmo acontece com o nosso pato: ele deve saber nadar para poder ser acessado pela interface Swimmable. Se ela não souber fazer isso, a interface Swimmablenão conectará os dois lados - a pessoa e o programa. Uma pessoa não será capaz de usar um método swim()para fazer um objeto Duckflutuar dentro de um programa. Agora você viu com mais clareza para que servem as interfaces. Uma interface descreve o comportamento que as classes que implementam essa interface devem ter. “Comportamento” é uma coleção de métodos. Se quisermos criar vários mensageiros, a maneira mais fácil de fazer isso é criando uma interface Messenger. O que qualquer mensageiro deveria ser capaz de fazer? De forma simplificada, receba e envie mensagens.
public interface Messenger{

     public void sendMessage();

     public void getMessage();
}
E agora podemos simplesmente criar nossas classes de mensageiro implementando esta interface. O próprio compilador nos “obrigará” a implementá-los dentro das classes. Telegrama:
public class Telegram implements Messenger {

    public void sendMessage() {

        System.out.println("Sending a message to Telegram!");
    }

     public void getMessage() {
         System.out.println("Reading the message in Telegram!");
     }
}
Whatsapp:
public class WhatsApp implements Messenger {

    public void sendMessage() {

        System.out.println("Sending a WhatsApp message!");
    }

     public void getMessage() {
         System.out.println("Reading a WhatsApp message!");
     }
}
Viber:
public class Viber implements Messenger {

    public void sendMessage() {

        System.out.println("Sending a message to Viber!");
    }

     public void getMessage() {
         System.out.println("Reading a message in Viber!");
     }
}
Que benefícios isso proporciona? O mais importante deles é o acoplamento fraco. Imagine que estamos projetando um programa no qual coletaremos dados de clientes. A classe Clientdeve possuir um campo indicando qual mensageiro o cliente utiliza. Sem interfaces pareceria estranho:
public class Client {

    private WhatsApp whatsApp;
    private Telegram telegram;
    private Viber viber;
}
Criamos três campos, mas um cliente pode facilmente ter apenas um mensageiro. Só não sabemos qual. E para não ficar sem comunicação com o cliente, é preciso “empurrar” todas as opções possíveis para a aula. Acontece que um ou dois deles sempre estarão lá nulle não são necessários para que o programa funcione. Em vez disso, é melhor usar nossa interface:
public class Client {

    private Messenger messenger;
}
Este é um exemplo de “acoplamento fraco”! Em vez de especificar uma classe de mensageiro específica na classe Client, simplesmente mencionamos que o cliente possui um mensageiro. Qual deles será determinado durante o curso do programa. Mas por que precisamos de interfaces para isso? Por que eles foram adicionados ao idioma? A pergunta é boa e correta! O mesmo resultado pode ser alcançado usando herança comum, certo? A classe Messengeré a classe pai e , Vibere Telegramsão WhatsAppos herdeiros. Na verdade, é possível fazê-lo. Mas há um problema. Como você já sabe, não existe herança múltipla em Java. Mas existem várias implementações de interfaces. Uma classe pode implementar quantas interfaces desejar. Imagine que temos uma turma Smartphoneque possui um campo Application- um aplicativo instalado em um smartphone.
public class Smartphone {

    private Application application;
}
O aplicativo e o mensageiro são, obviamente, semelhantes, mas ainda assim são coisas diferentes. O Messenger pode ser móvel e desktop, enquanto o Application é um aplicativo móvel. Portanto, se utilizássemos herança, não poderíamos adicionar um objeto Telegramà classe Smartphone. Afinal, uma classe Telegramnão pode herdar de Applicatione de Messenger! E já conseguimos herdá-lo Messengere adicioná-lo à classe neste formato Client. Mas uma classe Telegrampode implementar facilmente ambas as interfaces! Portanto, em uma classe Clientpodemos implementar um objeto Telegramcomo Messengere em uma classe Smartphonecomo Application. Veja como isso é feito:
public class Telegram implements Application, Messenger {

    //...methods
}

public class Client {

    private Messenger messenger;

    public Client() {
        this.messenger = new Telegram();
    }
}


public class Smartphone {

    private Application application;

    public Smartphone() {
        this.application = new Telegram();
    }
}
Agora podemos usar a classe Telegramcomo quisermos. Em algum lugar ele atuará no papel de Application, em algum lugar no papel de Messenger. Você provavelmente já percebeu que os métodos nas interfaces estão sempre “vazios”, ou seja, não possuem implementação. A razão para isso é simples: uma interface descreve o comportamento, não o implementa. “Todos os objetos de classes que implementam a interface Swimmabledevem poder flutuar”: isso é tudo que a interface nos diz. Como exatamente um peixe, pato ou cavalo nadará é uma questão para as classes Fish, Ducke Horse, e não para a interface. Assim como mudar de canal é tarefa de uma TV. O controle remoto simplesmente oferece um botão para fazer isso. No entanto, Java8 tem uma adição interessante: métodos padrão. Por exemplo, sua interface possui 10 métodos. 9 deles são implementados de forma diferente em classes diferentes, mas um é implementado da mesma forma em todas. Anteriormente, antes do lançamento do Java8, os métodos dentro das interfaces não tinham nenhuma implementação: o compilador gerava imediatamente um erro. Agora você pode fazer assim:
public interface Swimmable {

   public default void swim() {
       System.out.println("Swim!");
   }

   public void eat();

   public void run();
}
Usando a palavra-chave default, criamos um método na interface com uma implementação padrão. Precisaremos implementar os outros dois métodos, eat()e run()nós mesmos, em todas as classes que implementaremos Swimmable. Não há necessidade de fazer isso com o método swim(): a implementação será a mesma em todas as classes. A propósito, você já se deparou com interfaces mais de uma vez em tarefas anteriores, embora não tenha percebido :) Aqui está um exemplo óbvio: Por que precisamos de interfaces em Java - 2Você trabalhou com interfaces Liste Set! Mais precisamente, com suas implementações - ArrayList, LinkedListe HashSetoutros. O mesmo diagrama mostra um exemplo quando uma classe implementa várias interfaces ao mesmo tempo. Por exemplo, LinkedListele implementa as interfaces Liste Deque(fila dupla face). Você também está familiarizado com a interface Map, ou melhor, com suas implementações - HashMap. A propósito, neste diagrama você pode ver uma característica: as interfaces podem ser herdadas umas das outras. A interface SortedMapé herdada de Mape Dequeé herdada de queue Queue. Isto é necessário se você quiser mostrar a conexão entre interfaces, mas uma interface é uma versão estendida de outra. Vejamos um exemplo com uma interface Queue- uma fila. Ainda não examinamos as coleções Queue, mas elas são bastante simples e organizadas como uma linha normal de uma loja. Você pode adicionar elementos apenas ao final da fila e retirá-los apenas do início. A certa altura, os desenvolvedores precisavam de uma versão expandida da fila para que elementos pudessem ser adicionados e recebidos de ambos os lados. Foi assim que uma interface foi criada Deque- uma fila bidirecional. Ele contém todos os métodos de uma fila regular, porque é o “pai” de uma fila bidirecional, mas novos métodos foram adicionados.
Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION