Devo criar interfaces para objetos de transferência de dados?

19

É uma boa ou má idéia criar uma interface para objetos de transferência de dados? Presumindo que o objeto geralmente seja mutável.

Embora meu exemplo seja em Java, ele deve ser aplicável a qualquer outra linguagem que possua conceitos semelhantes.

interface DataTransferObject  {
    String getName();
    void setName(String name);
}

class RealDataTransferObject  implements DataTransferObject {

    String name;
    String getName() {
        return name;
    } 
    void setName(String name) {
        this.name = name;
    }
}

Obviamente, este é um exemplo simplificado, na vida real pode haver mais campos.

Archimedes Trajano
fonte

Respostas:

24

A resposta geral é não , porque você nunca deve adicionar código sem ter uma razão específica e concreta para isso, e não há uma razão geral para essa interface.

Dito isto, às vezes pode haver uma boa razão. Mas em todos os casos que eu vi, essas interfaces eram parciais, cobrindo apenas uma ou algumas propriedades compartilhadas por várias classes que eu queria usar polimorficamente, sem fornecer a elas uma superclasse comum. Candidatos típicos são uma Idpropriedade a ser usada em algum tipo de registro ou uma Namepropriedade a ser exibida para o usuário. Mas pode ser útil em qualquer caso em que você queira que algum código lide com tudo que tem um X - basta criar uma XSourceinterface que contenha os métodos getX(e, somente se necessário setX).

Mas uma interface separada para cada classe de modelo, contendo todas as propriedades? Não consigo imaginar uma boa razão para fazer isso. Um mau motivo seria uma estrutura mal projetada que requer isso; Os EJBs de entidade fizeram exatamente isso, se bem me lembro. Felizmente, eles eram tão ruins que nunca ganharam muita tração e estão obsoletos desde o EJB 3.0.

Nota: evite usar o termo "objeto de valor" para descrever os beans Java apenas com getters e setters triviais - ele entra em conflito com a definição mais comum de objeto de valor como algo sem identidade geralmente imutável. Um termo melhor seria DTO ou classe de modelo - embora, no último caso, observe que os modelos de domínio anêmico são considerados um antipadrão.

Michael Borgwardt
fonte
3
"modelos de domínio anêmico são considerados um antipadrão" - por Martin Fowler que, na PEAA, admite que conhece pessoas que trabalham dessa maneira há décadas "com muito sucesso". Assim, sugiro, menos um antipadrão e mais um não-como-Fowler gosta de trabalhar. No entanto, boa resposta, +1.
pdr
4
@pdr: Fowler pode ter cunhado o termo, mas ele não é o único que os considera um antipadrão. Eu não acho que alguém que realmente entendeu o OO pense que é uma boa idéia manter a lógica específica do domínio fora do modelo de domínio.
Michael Borgwardt 02/02
Obrigado pela correção do termo, DTO era a palavra que eu procurava ontem à noite, mas não conseguia lembrar a vida toda. Ao mudar o nome, as coisas fizeram mais sentido em termos de design.
Archimedes Trajano
@pdr Acho que a melhor maneira de dizer isso é que é um antipadrão no contexto da programação OO. Existem muitos outros paradigmas em que tudo está perfeitamente bem, e você pode trabalhar com êxito dessa maneira em uma linguagem OO (simplesmente não seria particularmente orientada a objetos).
Daniel B
3
@ MichaelBorgwardt: Eu concordo, ele não está sozinho nisso. Mas também não são pessoas que discordam. Se você dissesse que "alguns modelos de domínio anêmico são considerados por alguns como antipadrão", eu não teria dito nada. Francamente, acho que toda a sua resposta seria melhor sem o último parágrafo de qualquer maneira. A primeira metade teria feito um comentário melhor; a segunda metade não oferece nada para essa questão.
pdr
2

Criar interface está ok, mas NÃO da maneira que seu exemplo funciona. Você deve remover o setter da interface e tudo ficará bem:

interface ValueObject {
  String getName();
};

Isso permite muitas implementações diferentes, como o nome pode ser buscado no banco de dados ... O Setter deve estar em uma interface diferente.

tp1
fonte
2

Interfaces definem um contrato entre as classes que implementam as interfaces e seus clientes. Eles são usados ​​como um mecanismo de abstração para que os clientes possam manipular "coisas com um determinado comportamento".

Portanto, a resposta geral à pergunta "devo criar e usar essa interface?" é: Sim, se você pode associar um (um único) conceito que é semanticamente relevante para seus clientes.

Por exemplo, Comparable é uma boa interface, porque explica que as coisas podem ser comparadas graças a um de seus métodos e, como cliente, estou interessado em lidar com objetos comparáveis ​​(por exemplo, para classificá-los). Por outro lado, o CoolStuff não é uma boa interface se você admitir que os objetos legais não têm um comportamento específico (na verdade, você pode imaginar um software no qual lidar com objetos legais faz sentido, porque eles têm um comportamento comum como o beCool método).

No seu caso particular, acredito que sua interface é inútil. Quem o usará, como e quando? Você não pode criar uma interface para cada um dos valores mutáveis. Então, pergunte a si mesmo qual é a propriedade relevante e interessante por trás de seus métodos.

Se o que você deseja é lidar com objetos com todos os seus valores mutáveis ​​acessíveis por meio de dois métodos, dê uma olhada na noção de Java bean e na maneira como você pode forçar suas classes a adotar suas convenções.

mgoeminne
fonte
2

Como Michael disse, não adicione uma interface, a menos que você tenha uma necessidade específica.

O teste é um exemplo de uma boa razão. Embora eu prefira usar colaboradores reais se eles são apenas "objetos de valor", como você os chama, para um verdadeiro isolamento de teste de unidade, você pode precisar criar um objeto falso para teste, caso em que uma interface é bastante útil.

jhewlett
fonte
1
As interfaces não são necessárias para o uso de estruturas de simulação há séculos.
Michael Borgwardt 02/02
Parece que você está defendendo o monkeypatching. Eu estive nessa estrada com Moles em C # e não é bonito. Melhor passar seus colaboradores, se possível.
jhewlett
1
Embora as duas estruturas de zombaria que eu uso Mockito e easyMock não possam zombar das classes finais ao torná-las imutáveis.
Archimedes Trajano
1

Se você deseja que este objeto tenha algum tipo de validação de campos no futuro, você deve encapsulá-los nos estágios iniciais.

goodfella
fonte
0

A 'interface para o objeto de valor' é o que eu costumava chamar de acessador.

Eu experimentei políticas diferentes em relação à necessidade dos acessadores. Algumas pessoas defendem quando, tanto quanto possível, outras proíbem a redução da quantidade de código a ser escrita.

Algumas rações para acessadores (ou uso direto do valor) são as seguintes:

  • Os acessadores permitem alterar posteriormente a maneira como o valor é armazenado
  • Os acessadores permitem adicionar log de acesso quando você deseja depurar seu software (ao adicionar uma chamada de log em um único método, você captura todas as alterações de valor)
  • Os acessadores estão mais alinhados com a programação de objetos, cada variável sendo encapsulada por métodos
  • Os acessadores reduzem a expressividade do código (mais SLOC para o mesmo resultado)
  • Os acessadores usam alguma CPU

Eu pessoalmente advogo a reduzir o número de acessadores e usá-los quando você espera que o setter (setName) se torne mais do que uma simples afetação posteriormente.

Marc-Emmanuel Coupvent des Gra
fonte
0

Esse tipo de objeto de valor é de nível bastante baixo. Eu sugiro empurrá-lo em uma de duas direções: (1) tornar o objeto de valor imutável, ou seja, como um valor real , ou (2) elevar a mutabilidade a uma função de negócios orientada ao domínio de nível superior, o que significa que devemos expor interfaces em termos de unidades de funcionalidade relevantes ao domínio.

Erik Eidt
fonte