Interfaces

em 24/08/2003 , por Carlos Barth
Trabalhando com Interfaces
O grande estímulo ao uso de interfaces é um dos pontos fortes do Java, infelizmente este conceito é pouco compreendido, até mesmo entre programadores ?experientes?. Isto é possível porque utiliza conceitos de programação orientada a objetos que muitas vezes são deixados de lado por um grande número de programadores. De fato, para conseguir realmente compreender a utilidade (ou seria necessidade?) da utilização deste recurso, é preciso antes conhecer conceitos de programação orientada a objetos (é assustador o grande número de programadores que utilizavam Java de forma procedural). O conceito de Programação Orientada a Objetos deveria trazer inúmeros benefícios aos programadores, mas infelizmente muitos deles não conseguem compreender completamente os conceitos envolvidos, e acabam não conseguindo adaptar-se totalmente, resultado: seus códigos são totalmente mistos. Estes desenvolvedores muitas vezes vêem diversos conceitos OO de uma forma distorcida: ?Muito trabalho para pouco benefício? dizem, diante da idéia de criar classes e mais classes para realizar tarefas que antes podiam ser feitas em um único arquivo não muito grande. A idéia aqui não é abrir uma discussão sobre "diferentes tipos de programadores" e sim mostrar o motivo pelo qual muitos programadores conseguem compreender o recurso, mas não entendem porquê ou quando devem utilizá-lo. Para que alguém consiga utilizar interfaces efetivamente é necessário antes de tudo algum conhecimento concreto de programação orientada a objetos. Este artigo não visa ensinar conceitos de OO, ao contrário, assumimos aqui que você já tem algumas noções à este respeito.
Interfaces x Classes
Toda classe possui um propósito específico e (muito provavelmente) se relaciona com outras classes, formando assim um sistema completo e funcional. Quando escrevendo uma classe, podemos separar seus métodos em basicamente dois tipos: os de acesso público e os de acesso privado (esqueça os modificadores de acesso intermediários por hora). Quando um método é declarado público, significa que ele pode ser invocado por outros objetos, ao contrário de métodos privados que, geralmente, realizam tarefas ou processam informações as quais dizem respeito apenas ao funcionamento interno da classe em questão. Tomemos como exemplo uma classe chamada Funcionario:

Analisando o código acima nota-se que um objeto Funcionario se relaciona com outras classes de três maneiras: retornando seu nome, seu endereço e o valor de seu salário (a partir dos métodos getNome(), getEndereco() e getSalario()). Aos outros objetos, pouco importa como o objeto calcula estes valores. Para esta camada ?pública? é dado o nome de interface do objeto. Então, quando um objeto se relaciona com outro, ele não acessa seus recursos diretamente, mas sim através de sua interface.
Obs.: O termo ?relacionar? refere-se à capacidade dos objetos de ?transmitirem mensagens? entre si, ou seja, um objeto pode invocar métodos em outro, desde que estes métodos façam parte da interface daquele objeto. As vantagens deste conceito se revelam quando considerarmos a facilidade de manutenção, afinal, desde que a interface de um objeto não seja modificada (ou seja, desde que a assinatura de seus métodos públicos não mude) não há qualquer problema em alterar o funcionamento interno de uma classe (seus métodos e atributos privados), pois isto não irá exigir qualquer alteração nas demais classes do sistema , que se comunicam apenas através das interfaces (uma vez que os métodos com os quais ela se relaciona não foram modificados). Desta forma, utilizando a classe acima como exemplo em uma suposta migração da base de dados dos funcionários de um banco de dados para outro, as únicas alterações necessárias nos códigos do sistema serão as dos métodos atualizaDados() e também calculaSalario(), que acessam diretamente as bases de dados, como os demais objetos não conhecem e não utilizam estes métodos de qualquer forma, não há riscos em danificar a estrutura do sistema ao alterá-los.
Utilizando Interfaces em Java
Java estendeu o conceito de interfaces à um nível ainda mais flexível. Ao modelar um sistema, o desenvolvedor pode assim pensar apenas nas interfaces de seus objetos (ou seja, na função de cada um deles, e no seu relacionamento com os outros). Criando assim uma camada extra de abstração. Colocando em pratos limpos: O uso de interfaces faz com que você pense em objetos e o relacionamento entre eles, construindo assim a ?planta? do sistema de uma forma consistente e clara, depois disso, basta começar a ?construção? seguindo os moldes já existentes. Agora que já conhecemos o conceito principal, podemos começar a escrever código:

A sintaxe para definição de uma interface é extremamente semelhante à utilizada na definição de classes. Todos os métodos em uma interface são implicitamente abstratos (o equivalente à utilizar o modificador abstract em uma classe abstrata), e públicos. Assim, a interface Funcionario representa um ?molde? de tudo aquilo que será acessível à outras classes em um objeto do tipo Funcionario. Desta forma, qualquer classe que implemente esta interface, será também considerada do tipo Funcionario (o efeito é semelhante ao de sub-classear uma classe chamada Funcionario por exemplo). Interfaces não podem ter atributos (ou seja, variáveis membro), mas podem, no entanto possuir constantes definidas (variáveis que utilizam os modificadores static e final conjuntamente).

Uma vez definida, a interface é compilada normalmente (um arquivo .class é gerado, como se fosse uma classe qualquer). A sintaxe para implementação de uma interface por uma classe é a seguinte:

Uma classe pode ainda implementar mais de uma interface, neste caso, elas são colocadas lado a lado, separadas por vírgula juntamente com a cláusula implements. Quando uma classe implementa uma interface, ela deve obrigatoriamente implementar os métodos definidos na interface. O resultado é que você pode tratar objetos do tipo Pessoa como se fossem do tipo Funcionario. E com a possibilidade de a mesma classe implementar mais de uma interface, obtem-se um resultado semelhante ao de múltipla-herança, recurso inexistente na linguagem Java que permite uma classe ter várias super-classes (ou seja, ela pode ser de vários tipos diferentes). Assim, pode-se dizer que "uma pessoa é um funcionario" e criar códigos como:

O código abaixo não está completo, mas exemplifica uma situação onde o uso de interfaces pode ser utilizado para criar uma situação semelhante à de múltipla herança:

Um exemplo do mundo real
Uma vez entendidos os mecanismos do funcionamento de interfaces, é possível partir para um exemplo realista, onde interfaces podem ser utilizadas não apenas para simplificar as coisas como também poupar um bocado de trabalho: Uma empresa de desenvolvimento de softwares possui um sistema utilizando em controle de clínicas médicas de pequeno porte. O sistema é relativamente simples, utilizado apenas para cadastro e controle de pacientes da clínica, mantendo um histórico do cliente, bem como informações médicas importantes. Em uma ocasião, a mesma empresa fechou um contrato para o desenvolvimento de um novo software para uma clínica recém aberta. A única diferença é que esta clínica era veterinária, lidava com animais e não com pessoas. No mundo real, as clínicas trabalham de uma forma totalmente diferente, mas falando em software, o funcionamento é muito semelhante, quer dizer, a clínica veterinária também deseja manter histórico dos animais atendidos, bem como suas informações médicas (controle de vacinas etc.). Em suma, pode-se utilizar o sistema originalmente desenvolvido para clínicas gerais em clínicas veterinárias com algumas poucas adaptações. A estrutura do sistema era a seguinte:
O conjunto de classes acima foi criado para representar os pacientes de uma clínica, a classe PessoaJuridica é utilizada para representar cadastros de convênios com empresas. O problema é que animais possuem algumas características peculiares não possuídas por pessoas, e vice-versa. A solução foi então criar uma nova classe chamada Animal, para representar os animais da clínica:

Qual é o problema aqui?
O problema é que outras classes do sistema possuíam códigos como este:

Ou seja, seria necessário alterar todas as classes para que recebessem como parametro um objeto da classe Animal. Obrigando assim a empresa a manter duas versões diferentes de um software extremamente semelhante, o que implicava em trabalho dobrado à cada atualização e/ou modificação. A solução encontrada foi utilizar interfaces para realizar o que talvez deveria ter sido feito durante a modelagem inicial do sistema. Percebeu-se que, do ponto de vista do sistema, tanto Pessoas quanto Animais eram Pacientes. Assim, reuniu-se todos os métodos comuns à pacientes (independentes de serem pessoas ou animais, e colocou-se em uma interface com este nome:

Tanto a classe Animal quanto a classe Pessoa são pacientes, logo, o único código que teve de ser acrescentado à estas classes foi:

Permitindo obter códigos como:

Assim, ainda foi necessário alterar no sistema, os códigos que lidavam com objetos do tipo pessoa, para lidar agora com objetos do tipo Paciente. A vantagem é que o mesmo sistema poderia ser utilizado tanto por clínicas médicas quanto veterinárias sem causar um grande aumento de trabalho e eliminando a necessidade de se manter um sistema em separado.

A partir de agora, quando desenvolvendo um sistema, experimente pensar nos tipos que ira precisar (Pessoas, Cliente, Pacientes, Funcionarios etc.) crie suas interfaces e especifique o relacionamento entre eles. Você com certeza notará que conseguirá ver de antemão, muitos dos problemas de desenvolvimento que só seriam detectados no futuro, assim, quando tiver uma estrutura pronta, seu código ficará muito mais limpo e claro.