2010-02-28 12 views
29

¿Las entidades de dominio deberían estar expuestas como interfaces o como objetos simples?¿Las entidades de dominio deberían estar expuestas como interfaces o como objetos simples?

La interfaz de usuario:

public interface IUser 
{ 
    string FirstName { get; set; } 
    string LastName { get; set; } 
    string Email { get; set; } 
    Role Role { get; set; } 
} 

la implementación de usuario (Implementado en LinqToSql Data Access Layer):

public class User : IUser 
{ 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
    public string Email { get; set; } 
    public Role Role { get; set; } 
} 

la implementación de usuario (Implementado en NHibernate Data Access Layer):

[NHibernate.Mapping.Attributes.Class] 
public class User : IUser 
{ 
    [NHibernate.Mapping.Attributes.Property] 
    public string FirstName { get; set; } 

    [NHibernate.Mapping.Attributes.Property] 
    public string LastName { get; set; } 

    [NHibernate.Mapping.Attributes.Property] 
    public string Email { get; set; } 

    [NHibernate.Mapping.Attributes.Property] 
    public Role Role { get; set; } 
} 

esto solo ilustra algunas implementaciones específicas de DAL, no tiene una mejor muestra en este momento.

Respuesta

25

Mi opinión al respecto es que los objetos de dominio (no de dominio entidades, como el título lo indica algo que ver con una base de datos) no deben ser las interfaces a menos que tenga una razón muy convincente para creer que tendrá que soportar múltiples implementaciones en algún momento en el futuro.

Tenga en cuenta que el modelo de dominio es el modelo humano. El negocio/servicio/documento es, literalmente, el dominio. La mayoría de nosotros desarrolla software para un solo negocio o propósito. Si el modelo de dominio cambia, es porque las reglas comerciales han cambiado y, por lo tanto, el modelo de dominio anterior ya no es válido; no hay ninguna razón para mantener el anterior, ejecutándose junto con el nuevo.

El debate obviamente no es en blanco y negro. Es posible que esté desarrollando software que esté muy personalizado en varios sitios de clientes. Es posible que realmente necesite implementar diferentes conjuntos de reglas de negocios al mismo tiempo, y al mismo tiempo tenga una necesidad genuina de integrarlas en una arquitectura unificada. Pero, al menos en mi experiencia, estos casos son la excepción y no la regla, y aunque en general no me gusta el término, este podría ser un caso en el que deberías pensar en ti mismo, YAGNI.

El acceso a datos es un área común donde desea mejores abstracciones (persistence ignorance). En su ejemplo, tiene atributos NHibernate en su clase de modelo. Pero agregar atributos de persistencia hace que deje de ser una verdadera clase de dominio porque introduce una dependencia en NHibernate. NHibernate y Fluent NHibernate admiten mapeo de POCO utilizando una declaración de mapeo externo en lugar de atributos en la clase de datos, y este tiende a ser el enfoque preferido cuando se utilizan ORM como NHibernate o EF4, porque rompe la dependencia entre el modelo de persistencia y el modelo de dominio.

Si no fueron apoyados estos métodos de mapeo, y que tenía utilizar atributos, entonces podría sugerir el uso de las interfaces de hecho en su lugar, pero ORM hoy son más sofisticados que los que, mediante la reflexión y proxies dinámicos e intercepción método para hacerlo la mayor parte del trabajo pesado, por lo que no necesitas crear tus propias abstracciones aquí.

Algunos tipos de objetos que se le desea exponer como interfaces son:

  • repositorios, que son responsables de cargar/guardar objetos de dominio;
  • Complementos/extensiones de su programa;
  • Modelos de visualización/presentador, para que se puedan enchufar diferentes UI;
  • Tipos de datos abstractos con muchas implementaciones (matriz, lista, diccionario, conjunto de registros y tabla de datos son todas las secuencias AKA IEnumerable);
  • Operaciones abstractas con muchos algoritmos posibles (ordenar, buscar, comparar);
  • Modelos de comunicación (mismas operaciones sobre TCP/IP, canalizaciones con nombre, RS-232);
  • Cualquier cosa específica de la plataforma, si planea implementar en más de una (Mac/Windows/* nix).

que de ninguna manera es una lista completa, pero debe iluminar el principio básico aquí, y es que las cosas más adecuados para interconectar las abstracciones son las cosas que:

  1. dependerá de factores que pueden más allá de tu control;
  2. Es probable que cambie en el futuro; y
  3. Son funciones horizontales (se usan en muchas partes de la aplicación/arquitectura).

Una clase de dominio será ampliamente utilizada, pero no encaja en ninguna de las dos primeras categorías; no es probable que cambie, y usted tiene un control casi total sobre el diseño. Por lo tanto, a menos que las clases mismas asuman dependencias indirectas (que es una situación que debe intentar evitar siempre que sea posible), no realizaría el esfuerzo extra de crear una interfaz para cada clase en el modelo de dominio.

+0

@Aaronaught: Ok, para ORM específico, ahora supongo que estoy usando Características de FullText, usaré Lucene.NET que también usa Atributos. Y hasta donde sé, no hay forma de usar un mapeo externo de atributos como FluentNhibernate do. Entonces, ¿cuál es el mejor enfoque para mantener a mis entidades de dominio como verdaderas POCO? ¿Quizás las interfaces funcionan de esa manera? –

+0

@Yoann. B: No sabía que Lucene.NET usaba atributos de decorador; definitivamente no los requiere. Si desea utilizarlos, tiene dos opciones: (a) hacer que su modelo de dominio sea dependiente de Lucene.NET, lo que parece una mala idea (¿qué ocurre si quiere usar SQL FTS en su lugar?) ¿Qué sucede si una versión futura de ¿Lucene.NET admite POCOs?), O (b) mueve sus objetos de búsqueda y repositorios a un espacio de nombres/ensamblaje diferente y utiliza una herramienta como AutoMapper para convertirlos en objetos de dominio. De cualquier manera, no creo que la creación de interfaces para los objetos sea de gran ayuda. – Aaronaught

+0

@Aaronaught: ¿Dijiste que Lucene.NET no requiere atributos? es sobre otra pregunta que publiqué (http://stackoverflow.com/questions/2356593/lucene-net-and-poco-entities) pero ¿cómo se puede hacer sin usar atributos con Lucene.NET? –

1

Objetos simples, a menos que haya una interfaz común para una implementación que pueda cambiar. Para eso están las interfaces. Las clases de valor como Money o Address no entran en esa categoría.

Su interfaz de ejemplo no tiene ningún comportamiento más allá de getter/setter. Para eso no son las interfaces.

+0

Considero que este ejemplo específico es una entidad de dominio, en lugar de un objeto de valor, porque identifica a un usuario específico. Pero eso dependería del uso. –

+1

La misma conclusión para mí: entidad de dominio u objeto de valor, las interfaces permiten que las implementaciones cambien sin afectar a los clientes. – duffymo

6

Las interfaces normalmente se consideran "contratos" y, por lo tanto, definirían el comportamiento. El otro uso principal es para burlarse, de modo que podría proporcionar entidades de dominio que eran maquetas en lugar de proceder de una fuente de datos específica (y tener dependencias de esa fuente).

Para un objeto simple de transferencia de datos, no veo mucha utilidad para definir interfaces, pero estoy dispuesto a demostrar que está equivocado. Me gustaría ir con objetos simples para esto.

1

Una entidad en la mayoría de los casos no debe teclearse.

Una entidad define explícitamente una identidad única para otras entidades del mismo tipo. Una entidad de Orden ya debería tener una identidad que sea diferente de todas las otras entidades de Orden en el sistema. También puede dañar la identidad de una entidad si la modela a través de la herencia. Por ejemplo, supongamos que tiene un Customer e implementa Customer como AmericanCustomer. Dale todo el comportamiento y el estado necesarios para ser un cliente estadounidense (pista: ¡le encantan las compras!). Luego, más tarde, ese mismo Customer, con el mismo nombre, los mismos hábitos de compra, viaja a Japón. ¿Todavía son un AmericanCustomer? ¿Crea un nuevo JapaneseCustomer y copia todos los datos, incluida la ID de ese cliente en este nuevo tipo? Eso podría tener consecuencias ..

¿A ese mismo cliente todavía le encantan las compras? Eso puede o no ser cierto para el JapaneseCustomer.Sin embargo, ahora, de repente, en un solo vuelo reservado, este Customer es diferente. Otros objetos en el sistema solicitarán ese mismo Customer usando su identificación única y pueden terminar con una imagen diferente del objeto de lo que esperaban (un AmericanCustomer). Tal vez el Cliente se basa en el origen nacional en lugar de la ubicación actual. Eso podría resolver algunos de los problemas, pero también introducir otros nuevos.

Modele sus Entidades alrededor de su identidad. La identidad no se trata solo de campos de ID. Un modelo es más que eso. Las entidades deben tener un comportamiento significativo en forma de lógica comercial, sí, pero no son servicios. No debería preocuparse por el envío polimórfico a diferentes comportamientos. Lo que es más importante es cómo su sistema ve esta entidad a través de su identidad única. Evite pensar en tipos de entidades. Organiza en torno a las identidades en su lugar.

Cuestiones relacionadas