Thursday, 26 de July de 2007
Depois de fazer uma pesquisa pelos forums do MSDN Brasil, percebi que a galera não comenta muito sobre o uso de interfaces em seus projetos de software. Seria por falta de conhecimento de como usar, uma vez que o uso de interfaces requer um certo nivel de abstração? Seria pela falta de necessidade do uso? Ou dificuldade de usar?
Bem, qualquer que seja o motivo, achei interessante escrever esse artigo sobre o assunto, que não tem como objetivo desmistificar o uso de interfaces em projetos de software, mas sim abordar alguns conceitos que podem ajudar a convencer o desenvolvedor a fazer uso mais frequente de interfaces. A linguagem utilizada é o C# para ilustrar o artigo, mas onde houver uma diferença significativa com o VB.Net, então mostrarei os códigos relativos as duas linguagens.
O que é interface?
Para quem não domina OOP, quando se fala em interface a primeira coisa que vem a mente é a interface com o usuário, ou seja, telas, botões, caixas de texto, etc. Bem, tenho que concordar que isso não deixa de ser também uma interface mas, em OOP, o conceito de interface é bem diferente.
No MSDN voce vai encontrar que interfaces, da mesma maneira que classes, definem um conjunto de propriedades, métodos e eventos. Mas, diferentemente das classes, interfaces não proveem implementações. Pode-se dizer que uma interface é semelhante a uma classe abstrata.
Então, poderíamos ter:
public interface IminhaInterface
{
void Metodo1();
void Metodo2();
}
que seria semelhante a
public abstract class MinhaInterface
{
abstract public void Metodo1();
abstract public void Metodo2();
}
Note que, tanto a interface como a classe abstrata não implementam os dois métodos. Surge então a pergunta: então qual a diferença?
Podemos citar algumas pequenas diferenças:
Classe abstrata
- Pode ter ou não alguma implementação. Pode também ter variáveis membros, métodos não abstratos ou propriedades.
- Pode derivar de apenas uma classe base, mesmo que essa classe base seja abstrata, mas pode derivar de quants interfaces for necessario.
- Pode ter métodos e propriedades não publicos, ou seja, private ou protected.
- Pode ter métodos e membros estaticos (static) e definir constantes.
Interface
- Não tem implementações ou váriaveis membros.
- Só pode derivar de interfaces.
- Todos os membros são publicos.
- Não pode ter nenhum desses items.
Porque essas pequenas diferenças?
Uma comparação bastante utilizada para a definição de interfaces é que elas atuam como um contrato entre o cliente e o provedor do serviço (a classe que implementa a interface) no qual o cliente está interessado. Num contrato, todas as regras tem que estar muito bem definidas, ou seja, tudo tem que ser mostrado publicamente e nada pode ser escondido. Imagine só um contrato onde algumas informações estivessem escondidas ou mesmo escritas com as famosas "letras miudas". Desse modo, quando se fala em uma interface, ou contrato, o cliente pode seguramente se basear no que está escrito no contrato (interface) porque tudo o que está la escrito será cumprido pelo provedor dos serviços. Pensando dessa maneira, agora fica claro porque todos os membros de uma interface são publicos e muito bem definidos e porque na interface não consta nenhum detalhe da implentação. Mesmo que haja alterações na implementação, isso não afeta o cliente que se baseia numa interface que, por definição, é imutável. Isso também permite ao .Net prover um alto grau de desacoplamento entre o cliente e o provedor uma vez que a interface não tem nenhum conhecimento das implementações que ficam encapsuladas atras da interface, ou seja, no provedor (classes).
O provedor fica ivre para levar a efeito as implementações, contanto que o conteudo do contrato (interface) seja respeitado. Obviamente que o provedor pode fornecer muito mais do que consta no contrato, o que não faz diferença para o cliente pois não afeta a interface, mas nunca menos para que não haja quebra de contrato.
Surge então a pergunta: caso seja necessario, como extender as facilidades da interface? Uma vez que a interface pode estar sendo utilizada por outros clientes, a saida seria a utilização de outras interfaces ou, em outras palavras, o cliente fazer uso de multiplos contratos.
Implementando uma interface
Para implementar uma interface, o que a classe tem que fazer é derivar da interface e implementar todos os métodos definidos na interface.
Então teremos:
//C#
public interface IMinhaInterface
{
void Metodo1();
void Metodo2();
}
´ VB
Public Interface IminhaInterface
Sub Metodo1()
Sub Metodo2()
End IMinhaInterface
Note que o nome de interface deve iniciar com um I maiusculo.
Então, ao implementar a interface na classe, teremos:
// C#
public class MinhaClasse : IMinhaInterface
{
public void Metodo1(){......}
public void Metodo2(){.....}
// outras implementacoes
int Medoto3(){.......}
}
´VB
Public Class MinhaClasse
Implements IMInhaInterface
Public Sub Metodo1() Implements IminhaInterface.Metodo1
...
End Sub
Public Sub Metodo2() Implements IminhaInterface.Metodo2
...
End Sub
Perceba que os métodos implementados na classe, devem ser explicitamene declarados como publicos, uma vez que, por definição, todos os métodos da interface também o são.
Note como no VB.Net, a maneira de como declarar a implementação da interface é bem diferente do C#. Veja que em cada método há a necessidade de mostrar de a qual interface e qual o método que está sendo implementado. Surge então a pergunta: mas se o código já está mostrando que estou implementado o Médoto1, então porque repetir novamente na referencia IminhaImterface.Metodo1?
Essa é mais uma daquelas "vantagens" entre as muitas, que os programadores VB dizem existir sobre o C# (a eterna discussão).
O que sucede é que, se a assinatura do método e seu valor de retorno forem os mesmos da interface, então o programador pode mudar o nome do método.
Agora que já temos a interface e a classe que a implementa, para fazer uso da interface o que o cliente precisa fazer é instanciar um objeto que implemente essa interface e assinalar esse objeto á uma variável do tipo interface. Então vejamos uma construção de código usando interface:
IminhaInterface obj:
obj = new MinhaClasse():
obj.Metodo2():
Apesar do uso de interface prover uma certa indireção relativa a classe que a implementa, mesmo assim o cliente ainda precisa instanciar a classe, como pode ser visto no exemplo anterior. Dese modo, não há uma completa separação entre a interface e a sua implementação.
No COM, o cliente precisa apenas instanciar um ponteiro para a interface obtendo-se um maior grau de desacoplamento e, consequentemente, uma maior abstração.
Como os métodos de MinhaClasse são publicos, pode-se também utilizar o seguinte código para acessar os métodos:
MinhaClasse obj;
obj = new MinhaClasse();
obj.Metodo2();
Como essa construção é correta e, como já foi visto, mesmo quando fazemos uso de interface o cliente ainda precisa instanciar a classe que a implementa, acredito que seja essa uma das razões pelas quais os desenvolvedores não deem muita atenção ao uso de interfaces, principalmente aqueles que vem do mundo não OOP e tem uma maior dificuldade em abstrair conceitos.
Ou seja, pra que utilizar interfaces se posso fazer acesso direto aos métodos utilizando apenas a classe?
Bem, existe ai o principio das "boas práticas". Se voce quiser levar a sério o conceito de projeto de software baseado em componentes, então há a necessidade de aderir a algumas regras práticas e uma delas é sempre que possível, procurar separar a interface de sua implementação e, fazendo o uso de interfaces, prover um máximo de desacoplamento entre cliente e o provedor de serviços.
Voce poderá encontrar no site do MSDN mais detalhes sobre melhores práticas no projeto de software baseado em componentes.
Uma maneira de evitar o acesso direto aos método é a utilização da implementação explicita da interface no servidor, onde cada membro da interface é implementado utilizando o nome da interface.
public class MinhaClasse() : IMinhaInterface
{
void IminhaInterface.Metodo1(){....}
void IminhaInterface.Medoto2(){....}
}
Note que, nesse caso, as implementações dos métodos não mais utilizam a palavra public.
Desse modo, o cliente só poderá fazer o acesso aos métodos, via interface:
IminhaInterface obj;
obj = new MinhaClasse();
obj.Metodo2();
Se no cliente o desenvolvedor tentar instanciar a classe e assinalar o objeto â uma variável que não seja do tipo da interface, o compilador mostrará um erro, dizendo que a classe não contém o método em questão.
Com esse pequeno artigo espero estar contribuindo para que os desenvolvedores interessados em projetos de software baseados em componentes estejam mais aderentes as boas práticas de uso da plataforma .Net.
Autor: Carlos R. Lacerda. - Analista Senior
Trabalhando com .Net desde o ano 2000
Atualmente envolvido com VS.Net 2005
Coordenador do site www.byteshift.com
Para adicionar um comentário você deve efetuar o
login