Garantindo a consistência de uma Interface


Imagine que você possui uma interface que descreve a base para alguma funcionalidade do seu sistema. Como sabemos, a ideia de isolarmos a definição em uma interface serve para facilitar os testes, diminuir o acoplamento e melhorar a estensibilidade.

Quando construímos um tipo, muitas vezes pensamos em como garantir que ele sempre fique em um estado consistente, para que seja utilizado pela aplicação sem qualquer problema. Mas como garantir a consistência de um tipo como uma interface? Interfaces não possuem qualquer implementação, e com isso não há como escrever qualquer código para validar parâmetros, garantia de estado, etc.

Com a criação da interface, também não temos controle de quantas implementações dela serão criadas. Deixar a responsabilidade de garantir a consistência para os implementadores, corre-se o risco de que um deles não se preocupe com isso, prejudicando o propósito para qual a interface foi criada.

A Microsoft recentemente publicou um projeto chamado Code Contracts, e que podemos utilizar uma funcionalidade dele para suavizar esse problema. Através dos atributos ContractClassForAttribute e ContractClassAttribute, conseguimos amarrar (e separar) a nossa interface à uma classe utilizada exclusivamente para validar as implementações, que analisará em runtime se as condições estão ou não sendo atentidas. Abaixo temos uma interface para um repositório de domínio, e logo em seguida, temos uma classe apenas para garantir a sua consistência.

[ContractClass(typeof(RepositoryContract))]
public interface IRepository
{
    T GetById<T>(Guid id) where T : AggregateRoot;

    void Save(AggregateRoot item);
}

[ContractClassFor(typeof(IRepository))]
internal sealed class RepositoryContract : IRepository
{
    public T GetById<T>(Guid id) where T : AggregateRoot
    {
        return default(T);
    }

    public void Save(AggregateRoot item)
    {
        Contract.Requires<ArgumentNullException>(item != null);
    }
}

Note que utilizamos o atributo ContractClassAttribute para apontar qual a classe que representa o contrato, e mais abaixo, utilizamos o atributo ContractClassForAttribute para indicarmos que a classe onde este atributo está sendo aplicado serve como contrato para a interface apontada nele. E, finalmente, um detalhe interessante é que a classe é definida como internal, evitando assim o acesso direto pelos consumidores da interface.

Publicidade

2 comentários sobre “Garantindo a consistência de uma Interface

  1. Israel,

    não seria mais fácil utilizar uma classe abstrata? Desse modo vc poderia escrevar código na classe abastrata que verifica se o estado do objeto é valido, independente da classe concreta.

    []’s
    Eduardo Ernandes

Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s