Pregunta

Una cosa que veo en algunas aplicaciones empresariales DDD en las que trabajo es el uso de interfaces que son idénticas a las entidades de dominio, con un mapeo uno a uno de propiedades y funciones. De hecho, un objeto de dominio siempre se usa a través de su interfaz uno a uno, y todas las entidades de dominio tienen una interfaz uno a uno en este estilo.

Por ejemplo:

Cuenta de objeto de dominio:

public class Account : IAccount
{
     public string Name {get;set;}
     //...some more fields that are also in IAccount
     public decimal Balance {get;set;}
}

Y es una interfaz coincidente

public interface IAccount
{
   string Name {get;set;}
   //... all the fields in Account
   decimal Balance {get;set;}
}

Pero últimamente me he convencido cada vez más de que esto es, de hecho, un antipatrón.
Lo ejecuté por algunos arquitectos de la comunidad de código abierto, y dicen que esto se basa en errores o fallas de diseño, en algún lugar de la cadena de diseño.

Entonces les digo a mis colegas que deberían dejar de crear interfaces para los objetos de Dominio. Debido a que no tienen ningún propósito, y debe actualizar la interfaz cada vez que actualice las entidades de dominio.

Primero se hizo la afirmación de que estas interfaces proporcionan 'desacoplamiento', pero yo respondo que debido a que las interfaces tienen una relación de uno a uno con las entidades de dominio que realmente no proporcionan ningún desacoplamiento, un cambio en la interfaz significa un cambio en la entidad de dominio y viceversa.

La siguiente afirmación es que necesitamos las interfaces para realizar pruebas. Mi respuesta es que Rhino-mocks proporciona burlas y tropezones de clases concretas. Pero afirman que Rhino-mocks tiene problemas con las clases concretas. No sé si compro eso, incluso si rinoceronte tiene problemas con clases concretas, eso no significa necesariamente que debamos usar interfaces para las entidades de dominio.

Así que tengo curiosidad:

¿Por qué tendría interfaces uno a uno para sus entidades de dominio?

¿Por qué no?

¿Por qué es una buena o mala práctica?

¡Gracias por leer!

EDITAR : debo tener en cuenta que uso interfaces todo el tiempo, y creo que si es necesario, usaré una interfaz en un abrir y cerrar de ojos. Pero me refiero específicamente a las entidades de dominio con interfaces uno a uno.

¿Fue útil?

Solución

Es una mala práctica como se describe, pero ...

No hay una razón específica por la cual sus interfaces deben ser diferentes a las entidades de su dominio; A veces realmente es el mapeo correcto. Pero es sospechoso que siempre sea así. El motivo de preocupación es la cuestión de si las interfaces se diseñaron realmente o no, o si simplemente se colocaron en su lugar por falta de tiempo / pereza.

Para usar su ejemplo, la interfaz IAccount que describe expone getters y setters en el objeto Account; parece un poco extraño e improbable que todo lo que use una cuenta tenga que establecer el saldo en la cuenta, y que ese permiso implícito se especifique en ese nivel de interfaz. ¿No hay un lugar en su sistema en el que quiera simplemente verificar pero no establecer el saldo de la Cuenta?

Otros consejos

La razón más importante para especificar siempre los objetos de dominio como interfaces en lugar de directamente como clases es darle un grado de libertad en la implementación. En su ejemplo, solo tiene un tipo de IAccount, por lo que es un poco redundante.

Pero, ¿y si tuvieras, por ejemplo:

public class Account : IAccount { ... }       // Usual account, persistent
public class MockAccount : IAccount { ... }   // Test mock object
public class TransAccount : IAccount { ... }  // Account, not persistent
public class SimAccount : IAccount { ... }    // Account in a performance sim

y así sucesivamente?

Al definir los objetos de dominio como interfaces, puede reemplazar las implementaciones sin alterar su definición de dominio.

En general, si mis clases no van a formar parte de un patrón de diseño como Strategy o Visitor, no agrego interfaces.

Agregar interfaces es realmente útil para los patrones de diseño como Strategy y Visitor, pero en esos casos no copio a los getters y setters de las clases de dominio. En cambio, creo interfaces que son específicas para las interfaces de patrones de diseño que creo.

interface SomeStrategy {
   void doSomething(StrategyData data);
}

interface StrategyData {
   String getProperty1();

   String getProperty2();
} 

Eso me permite dejar que las clases de dominio implementen esas interfaces o usar el patrón Adaptador. Creo que este es un enfoque mucho más limpio que simplemente crear interfaces por el simple hecho de hacerlo.

El diseño siempre debe reducir la incertidumbre. La creación de interfaces no reduce la incertidumbre, de hecho, probablemente aumenta la confusión, ya que no tiene ningún sentido.

Las interfaces uno a uno en las entidades son un antipatrón

James Gregory lo puso mejor que yo aquí .

Estoy de acuerdo contigo. Las interfaces deben actuar como un contrato, por lo que no tiene ningún valor tener interfaces uno a uno con entidades de dominio. Puede ser útil si desea abstraer un determinado comportamiento. Pero, esto funcionará en ciertos casos.

¿Por qué este ha desaparecido?

Encuentro que tener una interfaz para un objeto de dominio, como dijo Charlie Martin, me permite elegir mi implementación.

Un ejemplo fundamental es el identificador (object.Id) para un objeto, esto será diferente dependiendo de dónde almacene ese objeto y la responsabilidad de crearlo puede o no depender de la implementación de los datos más adelante. En SQL Server, puede optar por un número automático, pero en el almacenamiento de tablas de Azure puede optar por un Guid, pero no desea tener que cambiar la lógica empresarial de su aplicación porque cambia dónde almacena sus datos.

Puedo o no elegir que mi objeto de dominio persista, o incluso lo use en la capa de presentación; depende del alcance de mi aplicación, que es el mejor. Pero agregar un conjunto de interfaces de dominio comunes en una capa común me permite escribir servicios contra ellos y reutilizarlos una y otra vez.

Repasaríamos el mismo argumento sobre lo que debería ser una dirección si no tuviéramos IAddress, los nuevos programadores estarían reescribiendo cosas para tarjetas de crédito si no fuera por ICreditCard.

La etiqueta anti-patrón es un mal uso del lenguaje, es una simplificación excesiva para describir el valor de las soluciones para tareas complejas y variadas.

Hay un lugar para la mayoría de los patrones, incluso el difamado Singleton, lo que significa que no es un "antipatrón", al menos en lo que sugiere el término.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top