2012-01-20 8 views
20

Estoy construyendo mi modelo de dominio y continuando con la refactorización. Mientras lo hago, descubro que me gustan las interfaces, ya que me permite crear métodos/controladores/vistas reutilizables para tipos concretos basados ​​en sus interfaces. Sin embargo, estoy descubriendo que estoy creando una interfaz cada vez que agrego una nueva propiedad a una de mis entidades de dominio.Me preocupa que agregue demasiadas interfaces

Por ejemplo, tengo una objeto MemberStatus que hereda de un resumen Entidad objeto que a su vez implementa la interfaz IIdentifiableEntity lo que significa que tiene una propiedad Id. MemberStatus también implementa la interfaz INamedEntity que significa que tiene un nombre de propiedad, la IOrderedEntity interfaz que significa que tiene una propiedad DisplayOrder y los IHasMembers interfaz que significa que tiene una colección de objetos miembros. Aquí está el código:

public class MemberStatus : Entity, INamedEntity, IOrderedEntity, IHasMembers 
{ 
    public string Name { get; set; } 
    public float DisplayOrder { get; set; } 
    public ICollection<Member> Members { get; set; } 
} 

public abstract class Entity : IIdentifiableEntity 
{ 
    public int Id { get; set; } 
} 

public interface IIdentifiableEntity 
{ 
    int Id { get; set; } 
} 

public interface INamedEntity 
{ 
    string Name { get; set; } 
} 

public interface IOrderedEntity 
{ 
    float DisplayOrder { get; set; } 
} 

public interface IHasMembers 
{ 
    ICollection<Member> Members { get; set; } 
} 

Ahora, esto parece funcionar bien ya que otros objetos similares, tales como MemberPosition y MemberTeam la que todos implementan estas mismas interfaces y puedo usar mis métodos de depósito y acciones del controlador con los genéricos que implementan estas interfaces y tienen mucha reutilización de código.

Sin embargo, mi preocupación es si es apropiado o no seguir agregando interfaces simples de una sola propiedad cada vez que agregue una propiedad nueva a mis objetos concretos. Por ejemplo, supongamos que deseo agregar una propiedad bool Enabled ... ¿Debería continuar creando una interfaz IEnabled? La razón por la que estoy preguntando es que algunos de los "inicializadores" de controladores que usan genéricos son cada vez más largos, como se muestra en la siguiente línea de código. ¿Es esto normal y la mejor práctica?

public abstract class OrderedCrudController<TEntity> : CrudController<TEntity> where TEntity : Entity, INamedEntity, IOrderedEntity, IHasMembers, new() 

Respuesta

19

El hecho de que esté utilizando interfaces es algo bueno. Sin embargo, debería preguntarse, si creo una interfaz IEnabled, ¿alguna vez haré referencia a mi clase únicamente por esa interfaz? es decir, ¿habrá contextos en los que interactúo con mi clase solo a través de la propiedad única que expone la interfaz?

Además, ¿puede considerar los contextos en los que interactuará con la implementación múltiple de esta interfaz IEnabled?

Si la respuesta a ambas preguntas es "no", la interfaz tiene muy poco sentido.

Habiendo dicho eso, ¡no se preocupe demasiado por esto! hace muy poco daño.

+0

Gracias Colin. Pregunta rápida ... ¿sería más apropiado para mí crear una clase abstracta llamada algo así como ** MemberPropertyEntity ** (que implementa las mismas interfaces que muestro arriba para MemberStatus) que luego heredarán MemberStatus, MemberPosition, MemberTeam (y por lo tanto, casi no tendría código en ellos directamente)? Mi inicializador de controlador solo necesitaría tener una cláusula 'donde TEntity: MemberPropertyEntity '. ¿Es esto mejor que tener controladores con un montón de requisitos de interfaz? – bigmac

+0

@bmccleary Seguro: es un patrón relativamente común tener interfaces que son comunes a todas las entidades, como IHavePrimaryKey, pero implementan esta interfaz en una clase base abstracta. Sin embargo, mi punto original sigue en relación con interfaces como IEnabled, si nunca se refiere a tipos solo por esa interfaz, es de poca utilidad. – ColinE

+0

Gracias Colin, ¡lo aprecio! – bigmac

15

No cree interfaces que no prevé una necesidad inminente. Observe el principio YAGNI (no lo va a necesitar). De lo contrario, terminará con un código innecesariamente complicado.

+0

Gracias ... a veces es bueno recordar no complicar demasiado las cosas. – bigmac

3

Creo que su problema es que usted está tratando de calzador su modelo de dominio en cualquier interfaz gráfica de usuario que se esté viendo los datos en.

En su lugar, tenga en cuenta sus cosas objeto de dominio que tienen un comportamiento cercano a los datos y en su c'tor, dale un Action<DomainEvent>. Ahora, asegúrese de SOLAMENTE ALGUNA VEZ pasar datos de un objeto de dominio a través de esta acción.

Ahora, usted escucha.Siempre que en realidad desee realizar un cambio en su dominio, llame a un método. Deje que su interfaz gráfica de usuario se actualiza a través de la Action<DomainEvent> mediante la adopción de estos eventos y guardarlos en cualquier modelo de lectura que le interesa.

un vistazo a http://www.infoq.com/presentations/ddd-eric-evans y considerar sus puntos acerca de los eventos de dominio.

Ahora ya no tiene que agregar interfaces extrañas relacionadas con un dominio técnico en su dominio comercial. Y recuerda; si está haciendo CRUD como muestra su ejemplo, entonces NO está haciendo un diseño impulsado por el dominio. Usted tiene un dominio anémico.

Punto final: utilice interfaces para cosas que realmente necesitan ser intercambiables. ¿Está cargando muchas cosas en su aplicación INamed que pueden intercambiarse entre sí?

Permítanme también vinculan esto, para que usted considere:

+0

gracias por la información. Me da bastante para leer. Nunca estudié DDD, así que veré todo lo que esto implica y usaré tus enlaces como referencia. – bigmac

+0

+1 por mencionar el modelo de dominio. – ColinE