2010-11-17 24 views
6

Personalmente, no tengo mis entidades implementan interfaces. Para una clase Task, no tendría ITask que tuviera las mismas propiedades definidas en ella.¿Deberían las entidades implementar interfaces?

Lo he visto varias veces, así que me pregunto de dónde proviene ese consejo, y qué beneficios obtienes de él.

Si está utilizando un ORM, entonces el argumento que dice "Puedo cambiar el acceso a mis datos" es irrelevante, entonces, ¿qué otra razón hay para hacer esto?

ACTUALIZACIÓN:
Un buen punto se hizo en los comentarios sobre INotifyPropertyChanged. Esa no era mi punto, sin embargo - Estoy hablando de tener algo como esto:

public interface ITask 
{ 
    int Id { get; set; } 
    string Description { get; set; } 
} 

public class Task : ITask 
{ 
    public int Id { get; set; } 
    public string Description { get; set; } 
} 
+0

Una palabra: INotifyPropertyChanged – slugster

+0

Esto debe necesitar algunas más etiquetas. – bmargulies

+0

@bmargulies Por favor, siéntase libre de volver a etiquetar si lo desea. No quería que esto fuera específico del idioma y las "mejores prácticas" ya no se recomiendan como una etiqueta, por lo que no estaba seguro de qué más usar. –

Respuesta

3

Fui por esta carretera una vez (interfaces para objetos de valor). Era un dolor real en la parte trasera, recomendé no hacerlo. Los argumentos comunes para esto son:

Burlarse: Son objetos de valor. Nada para burlarse. Además burlarse termina siendo un gran dolor que escribir un constructor (en Java) o usar los argumentos nombrados en C#.

vistas de solo lectura: debo admitir que todavía prefieren hacer algo inmutable por defecto, sólo por lo que es mutable, si es absolutamente necesario.

Funcionalidad oculta: En general, el alcance ha cubierto este para mí.

+0

Sin olvidar también que XmlSerializer se niega rotundamente a serializar interfaces o deserializar a una interfaz. –

+0

¿Cómo se hace el segundo punto (vistas de solo lectura) sin utilizar la interfaz? –

+0

Por lo general, hago las cosas inmutables por defecto. Otra clonación antes de entregar algo "inseguro" o suministrar una interfaz de solo lectura. –

1

La principal ventaja de esto es que es una manera de exponer su entidad como una versión de "sólo lectura" (como se siempre y cuando su interfaz no exponga setters, por supuesto).

1

Estamos haciendo bastante pruebas unitarias y con frecuencia queremos simular cosas que no estamos probando. Aunque no me gusta, hemos terminado usando interfaces en todas partes porque hace que sea mucho más fácil burlarse de las cosas.

En teoría, la mayoría de los frameworks burlones también pueden simular clases normales, pero en la práctica esto nos ha causado problemas porque a veces hacemos cosas inteligentes con la reflexión y el tipo de la clase burlada no es igual al original. Para hacerlo:

var myTask = MyIoCProvider.Get<Task>(); 
var taskType = typeof(myTask); 

Era impredecible. Considerando que:

var myTask = MyIoCProvider.Get<ITask>(); 
var taskType = typeof(myTask); 

Le da como taskType que definitivamente se deriva de ITask.

Así que las interfaces solo nos dan una manera de hacer que nuestro sistema sea más burlable.

+0

Ya veo. Sin embargo, ¿por qué devolverías entidades desde tu contenedor IoC? ¿Estamos hablando de pruebas unitarias de objetos de dominio de datos y comportamientos completos que tienen dependencias en otros objetos de dominio y desea simular esas dependencias? –

+0

En nuestro caso, tenemos una distinción entre objetos de datos como "Tarea" y objetos de lógica de negocios como "TaskAssignmentManager". Los objetos de datos puros no tienen lógica, por lo que no necesitan burlarse, IoC o interfaces. Si tuviéramos objetos de dominio que tuvieran lógica y datos, creo que terminaríamos con interfaces sobre ellos. – d4nt

0

Si estaba pensando en términos de usar DomainEvents que las estructuras de datos tales como la tarea realmente es necesario implementar una interfaz

public interface IDomainEvent 
{ 
    Guid EventId { get; } 
    Guid TriggeredByEvent { get; } 
    DateTime Created { get; } 
} 

public class OrderCancelledEvent : IDomainEvent 
{ 
    Guid EventId { get; set; } 
    Guid TriggeredByEvent { get; set; } 
    DateTime Created { get; set; } 
    // And now for the specific bit 
    int OrderId { get; set; } 
} 

O Del mismo modo, si usted tiene una capa de acceso de datos común que puede que tenga que tomar en una clase base estándar de IEntity, pero no tendría una interfaz para cada tipo si solo se trata de una estructura de datos como usted describe en su publicación.

Cuando maneja objetos de dominio que realmente exponen el comportamiento, es posible que desee tener una interfaz para probar la unidad.

Cuestiones relacionadas