Interfaces
Interfaces se assemelham a classes abstratas. Se você entendeu bem o tópico sobre elas, não terá problemas aqui.
Vamos imaginar a seguinte situação: você está desenvolvendo uma aplicação para uma empresa que fabrica aparelhos eletrônicos diversos, como televisores, DVD Players, Tablets, Computadores e aparelhos de som.
É previsível que, como programador e diante dessa situação, você já comece a imaginar seu código contendo as classes "Televisor", "DVDPlayer", "Tablet", "Computador" e "AparelhoSom" e, em cada uma delas você fará planos para colocar as particularidades de cada um. Isso seria o que a maioria dos programadores pensaria e não está errado fazê-lo.
No entanto, algumas funções são comuns a todos os aparelhos citados, como, por exemplo, ligar e desligar e, se todos os aparelhos farão essas duas funções, é importante que não esqueçamos de cria-las em todas as classes e também seria interessante padroniza-las. Bem, é aí que entra a Interface. Seu papel é obrigar que todas as classes que “herdem” (esse não é o termo mais adequado para Interfaces, mas por enquanto deixemos assim) a Interface tenham que implementa-las.
Até aqui estamos diante das mesmas condições de uma classe abstrata, mas as diferenças começam a surgir agora. Uma classe abstrata pode conter métodos não abstratos, portanto com suas implementações feitas, enquanto em uma Interface isso não é possível. As Interfaces somente possuem assinaturas de métodos. Nelas os construtores também não são permitidos e, como ela não pode ser instanciada, eles também não são necessários. Vamos a um exemplo com códigos, para que tudo fique mais claro:
Vejam que, diferentemente de uma classe abstrata com métodos não abstratos, as Interfaces não aceitam corpo nos métodos:
Agora criarei uma classe chamada "DVDPlayer", que herdará essa simples Interface, vejam:
Agora vejam a questão da obrigatoriedade da implementação dos métodos. Vou tentar compilar essa aplicação e executa-la, mesmo sem ter criado, na classe "DVDPlayer", os métodos liga() e desliga(). Vejamos o que acontece:
O compilador identifica que os métodos não foram criados e exibe a mensagem de erro. Bem, até aí não vemos diferenças em relação a uma classe abstrata, mas agora já darei um exemplo de algo que diferencia uma Interface. Em C#, assim como em algumas outras linguagens, não é possível fazer herança múltipla, ou seja, herdar mais de uma classe. No entanto é possível herdar de várias Interfaces e isso pode, na maior parte dos casos, solucionar qualquer necessidade de herança múltipla que você tenha. Vou criar uma Interface qualquer, chamada de ITeste e criar nela um método Teste(), conforme a figura abaixo.
Agora farei a herança múltipla dessa Interface, na classe "DVDPlayer", vejam:
E vejam como tudo funciona perfeitamente. Vou tentar compilar a aplicação agora:
Percebam que não foi possível, pois o compilador identificou que o método Teste(), presente na Interface ITeste não foi criado, ou seja, a herança múltipla funcionou corretamente.
Outro ponto importante a se destacar sobre as Interfaces é que elas não aceitam nenhum tipo de modificador de acesso, ao contrário das classes abstratas. Vejam o que acontece quando tentamos utilizar algum:
Para utilizarmos métodos da classe que herdou de uma Interface basta realizarmos o procedimento comum de instanciação, conforme o exemplo abaixo:
Basicamente o que diferencia uma classe abstrata de uma Interface é que nas classes abstratas você pode fazer uso dos modificadores de acesso e nelas nem todos os métodos precisam ser abstratos, ou seja, você pode ter métodos que não precisam ser implementados nas subclasses, pois já possuem seu corpo na própria superclasse.
A Interface cria um “contrato” entre as partes envolvidas, ou seja, você obrigatoriamente terá de implementar as assinaturas de todos métodos contidos nela, mas a forma como o fará é por sua conta. Como fica fácil perceber, as Interfaces surgiram para promover a padronização de métodos.
E conforme citei no início deste tópico, não é comum usar o termo “herdar de uma Interface” ou “herdar uma interface”, como eu utilizei por várias vezes. Só o fiz para não quebrar o raciocínio que escolhi para explicar esse importante assunto e não ter que descrever, ainda no início, o que, de fato, fazia a Interface, pois isso poderia confundir mais do que ajudar. O comum é utilizar o termo “assinar uma Interface”, ou ainda “implementar uma Interface”.
Apenas para encerrar, é importante saber que é possível herdar de uma classe abstrata e de interfaces simultaneamente. A única restrição é que, após o sinal de dois pontos (:), que determina o início das entidades que serão herdadas, a classe deve ser citada antes das Interfaces, conforme a figura abaixo:
É isso!