¿Debo crear interfaces para objetos de transferencia de datos?

19

¿Es una buena idea o una mala idea crear una interfaz para objetos de transferencia de datos? Suponiendo que el objeto suele ser mutable.

Aunque mi ejemplo está en Java, debería ser aplicable a cualquier otro lenguaje que tenga conceptos similares.

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;
    }
}

Por supuesto, este es un ejemplo simplificado, en la vida real puede haber más campos.

Arquímedes Trajano
fuente

Respuestas:

24

La respuesta general es no , porque nunca debe agregar código sin tener una razón específica y concreta, y no hay una razón general para tal interfaz.

Dicho esto, a veces puede haber una buena razón. Pero en todos los casos que he visto, estas interfaces eran parciales, cubriendo solo una o unas pocas propiedades compartidas por múltiples clases que quería usar polifórficamente sin darles una superclase común. Los candidatos típicos son una Idpropiedad para usar en algún tipo de registro o una Namepropiedad para mostrar al usuario. Pero puede ser útil en cualquier caso en el que desee que algún código maneje todo lo que tiene una X: simplemente cree una XSourceinterfaz que contenga los métodos getX(y, si es necesario, los setX).

¿Pero una interfaz separada para cada clase de modelo, que contiene todas las propiedades? No puedo imaginar una buena razón para hacer eso. Una mala razón sería un marco mal diseñado que lo requiera; La entidad EJB hizo exactamente eso, si no recuerdo mal. Afortunadamente, fueron tan malos que nunca ganaron mucha tracción y están en desuso desde EJB 3.0

Nota al margen: evite usar el término "objeto de valor" para describir los beans Java con solo captadores y establecedores triviales; entra en conflicto con la definición más común de objeto de valor como algo sin identidad que generalmente es inmutable. Un término mejor sería DTO o clase de modelo, aunque en el último caso tenga en cuenta que los modelos de dominio anémico se consideran un antipatrón.

Michael Borgwardt
fuente
3
"Los modelos de dominio anémico son considerados un antipatrón", por Martin Fowler quien, en PEAA, admite que conoce a personas que han trabajado de esa manera durante décadas "con mucho éxito". Por lo tanto, sugiero, menos un antipatrón y más un no cómo Fowler le gusta trabajar. Sin embargo, buena respuesta, +1.
pdr
44
@pdr: Fowler puede haber acuñado el término, pero de ninguna manera es el único que los considera un antipatrón. No creo que nadie que realmente haya entendido OO piense que es una buena idea mantener la lógica específica del dominio fuera del modelo de dominio.
Michael Borgwardt
Gracias por el término corrección, DTO fue la palabra que estaba buscando anoche pero no podía recordar por mi vida. Al cambiar el nombre, las cosas tenían más sentido en cuanto al diseño.
Arquímedes Trajano
@pdr Creo que la mejor manera de decirlo es que es un antipatrón en el contexto de la programación OO. Hay muchos otros paradigmas en los que está perfectamente bien, e incluso podría funcionar con éxito de esa manera en un lenguaje OO (simplemente no estaría particularmente orientado a objetos).
Daniel B
3
@MichaelBorgwardt: Estoy de acuerdo, no está solo en eso. Pero tampoco lo son las personas que no están de acuerdo. Si hubiera dicho que "los modelos de dominio anémico son considerados por algunos como un antipatrón", no habría dicho nada. Francamente, creo que toda su respuesta sería mejor sin el último párrafo de todos modos. La primera mitad habría hecho un mejor comentario; La segunda mitad no ofrece nada a esta pregunta.
pdr
2

Crear una interfaz está bien, pero NO la forma en que funciona su ejemplo. Debes eliminar el setter de la interfaz, y estará bien:

interface ValueObject {
  String getName();
};

Esto permite muchas implementaciones diferentes, como el nombre se puede obtener de la base de datos ... Setter debe estar en una interfaz diferente.

tp1
fuente
2

Las interfaces definen un contrato entre las clases que implementan las interfaces y sus clientes. Se utilizan como un mecanismo de abstracción para que los clientes puedan manipular "cosas que tienen un comportamiento determinado".

Entonces, la respuesta general a la pregunta "¿debería crear y usar esta interfaz?" es: Sí, si puede asociar un concepto (uno único) que sea semánticamente relevante para sus clientes.

Por ejemplo, Comparable es una buena interfaz, porque explica que las cosas se pueden comparar gracias a uno de sus métodos, y como cliente, estoy interesado en tratar con objetos comparables (por ejemplo, para ordenarlos). Por el contrario, CoolStuff no es una buena interfaz si admite que los objetos geniales no tienen un comportamiento específico (de hecho, puede imaginar un software en el que tenga sentido tratar con objetos geniales, porque tienen un comportamiento común como un beCool método).

En su caso particular, creo que su interfaz es inútil. ¿Quién lo usará, cómo y cuándo? No puede crear una interfaz para cada uno de los valores mutables. Entonces pregúntese cuál es la propiedad relevante e interesante detrás de sus métodos.

Si lo que quiere es tratar con objetos con todos sus valores mutables accesibles a través de un par de métodos, eche un vistazo a la noción de Java Bean y la forma en que puede obligar a sus clases a adoptar sus convenciones.

mgoeminne
fuente
2

Como dijo Michael, no agregue una interfaz a menos que tenga una necesidad específica.

La prueba es un ejemplo de una buena razón. Aunque prefiero usar colaboradores reales si son simplemente "objetos de valor" como los llama, para un verdadero aislamiento de prueba de unidad puede que necesite crear un objeto falso para probar, en cuyo caso una interfaz es bastante útil.

jhewlett
fuente
1
Las interfaces no han sido necesarias para usar marcos burlones en años.
Michael Borgwardt
Parece que estás abogando por el mono parcheado. He recorrido ese camino con Moles en C # y no es bonito. Es mejor pasar a sus colaboradores si es posible.
jhewlett
1
Aunque los dos marcos burlones que uso Mockito y easyMock no pueden burlarse de las clases finales cuando las hago inmutables.
Arquímedes Trajano
1

Si desea que este objeto tenga algún tipo de validación de campos en el futuro, debe encapsularlos en las primeras etapas.

goodfella
fuente
0

La 'interfaz para objeto de valor' es lo que estoy acostumbrado a llamar a un descriptor de acceso.

Experimenté diferentes políticas con respecto a la necesidad de los accesos. Algunas personas abogan por el mayor tiempo posible, otras prohíben reducir la cantidad de código para escribir.

Algunas razones para los accesores (o el uso de valor directo) son las siguientes:

  • Accessors permite cambiar más tarde la forma en que se almacena el valor
  • Accessors permite agregar el registro de acceso cuando desea depurar su software (cuando agrega una llamada de registro en un solo método, captura cada cambio de valor)
  • Los accesores están más en línea con la programación de objetos, cada variable encapsulada por métodos
  • Los accesores reducen la expresividad del código (más SLOC para el mismo resultado)
  • Accessors toma algo de CPU

Personalmente abogo por reducir el número de accesores y usarlos cuando espere que el setter (setName) se convierta en algo más que una simple afectación posterior.

Marc-Emmanuel Coupvent des Gra
fuente
0

Este tipo de objeto de valor tiene un nivel bastante bajo. Sugeriría empujarlo en una de dos direcciones: (1) hacer que el objeto de valor sea inmutable, es decir, como un valor real , o (2) elevar la mutabilidad a una función comercial orientada al dominio de nivel superior, lo que significa que debemos exponer interfaces en términos de unidades de funcionalidad relevantes del dominio.

Erik Eidt
fuente