2010-11-23 16 views
29

Tuve una discusión en el trabajo con respecto a "La herencia en el modelo de dominio está complicando la vida de los desarrolladores". Soy un programador de OO, así que comencé a buscar argumentos de que tener herencia en el modelo de dominio facilitaría la vida del desarrollador en realidad en lugar de tener conmutadores por todos lados.Herencia vs propiedades enum en el modelo de dominio

Lo que me gustaría ver es la siguiente:

class Animal { 

} 

class Cat : Animal { 

} 

class Dog : Animal { 

} 

Lo otro colega está diciendo es:

public enum AnimalType { 
    Unknown, 
    Cat, 
    Dog 
} 

public class Animal { 

    public AnimalType Type { get; set; } 

} 

¿Cómo convencerlo (enlaces son BIENVENIDOS) que una clase jerarquía sería mejor que tener una propiedad enum para este tipo de situaciones?

Gracias!

+3

¿Es esto para un modelo de objeto en memoria o un ORM? No creo que el ejemplo de Animals sea muy útil, ya que no ejerce muchos de los problemas comunes que enfrenta al hacer un diseño de OO real. –

+0

@Marcelo: de acuerdo. Específicamente, ¿cuál es el ángulo de comportamiento? – sfinnie

+0

Los perros ladran, los gatos merodean, usando la implementación de su colega, estos comportamientos serán difíciles de implementar en C# (por ejemplo). Todavía es útil en lenguajes funcionales como F # donde las uniones discriminadas son un medio muy poderoso para proporcionar polimorfismo. –

Respuesta

24

Así es como puedo razón de ello:

Utilice sólo la herencia si el papel/Tipo nunca va a cambiar. p.

utilizando la herencia para cosas como:

bombero < - Empleado < - persona está equivocada.

tan pronto como Freddy el bombero cambie de trabajo o quede desempleado, tienes que matarlo y recrear un nuevo objeto del nuevo tipo con todas las relaciones antiguas asociadas.

Por lo tanto, la solución ingenua al problema anterior sería otorgarle una propiedad JobTitle enum a la clase de persona. Esto puede ser suficiente en algunos escenarios, p. si no necesita comportamientos muy complejos asociados con el rol/tipo.

La forma más correcta sería darle a la persona una lista de roles. Cada función representa, por ejemplo, un empleo con un lapso de tiempo.

p. Ej.

freddy.Roles.Add(new Employement(employmentDate, jobTitle)); 

o si eso es una exageración:

freddy.CurrentEmployment = new Employement(employmentDate, jobTitle); 

De esta manera, Freddy puede convertirse en un desarrollador w/o que tener que matarlo primero.

Sin embargo, todas mis divagaciones aún no han respondido si debe usar una enumeración o jerarquía de tipos para el título de la tarea.

En pure in mem OO Diría que es más correcto usar herencia para los títulos de trabajo aquí.

Pero si está haciendo un mapeo O/R, puede terminar con un modelo de datos supercomplejo entre bastidores si el asignador intenta asignar cada subtipo a una nueva tabla. Entonces, en tales casos, a menudo prefiero el enfoque enum si no existe un comportamiento real/complejo asociado con los tipos. Puedo vivir con un "tipo si == JobTitles.Fireman ..." si el uso es limitado y hace las cosas más fáciles o menos complejas.

p. Ej. el diseñador de Entity Framework 4 para .NET solo puede asignar cada subtipo a una nueva tabla. y es posible que obtenga un modelo feo o una gran cantidad de combinaciones cuando consulte su base de datos sin ningún beneficio real.

Sin embargo, sí uso la herencia si el tipo/rol es estático. p. para Productos.

es posible que tenga CD < - Producto y libro < - Producto. La herencia gana aquí porque en este caso es muy probable que tenga un estado diferente asociado con los tipos. El CD puede tener varias pistas de propiedad, mientras que un libro puede tener varias páginas de propiedad.

Así que en resumen, que depende ;-)

Además, al final del día, lo más probable es terminar con una gran cantidad de sentencias switch de cualquier manera. Digamos que desea editar un "producto", incluso si se utiliza la herencia, es probable que tenga un código como éste:

si (el producto es libro) Response.Redicted ("? ~/EditBook.aspx id" + producto.id);

Debido a que codifica la URL de edición de libros en la clase de entidad sería feo llano, ya que obligaría a sus negocios ENTIDADES saber sobre la estructura del sitio, etc.

+0

Logramos tener "Herencia tabla por jerarquía" (http://msdn.microsoft.com/en-us/library/bb738443.aspx) en EF 4 por lo que las consultas no son tan feas. –

+0

Sí, la tabla por jerarquía hace que la base de datos sea un poco más hábil, sin embargo, ¿cuánto xml tenía que escribir para que funcione? podría ser más que la declaración de cambio, solo decir. –

+0

Evitamos escribir primero xml con base de datos y luego crear el resto de las entidades asignadas a mano y asignarlas a la tabla wright. –

1

Lo más importante es que OOPS significa modelar la realidad. La herencia te da la oportunidad de decir que Cat es un animal. Animal no debería saber si ahora es un gato el que grita y luego decide que se supone que maulla y no ladra, la encapsulación es derrotada allí. Menos código ya que ahora no tienes que hacer Si no, como dijiste.

6

enumeraciones son buenos cuando:

  1. El conjunto de valores es fijo y nunca o muy raramente cambia.
  2. Desea poder representar una unión de valores (es decir, combinar indicadores).
  3. No necesita adjuntar otro estado a cada valor. (Java no tiene esta limitación.)

Si puede resolver su problema con un número, es probable que una enumeración sea adecuada y más segura. Si necesita más flexibilidad que la anterior, entonces las enumeraciones probablemente sean no la respuesta correcta. Utilización de las clases polimórficas, puede:

  1. asegurar estáticamente que todo el comportamiento específico del tipo se maneja. Por ejemplo, si necesita todos los animales para poder Bark(), hacer clases Animal con un método abstracto Bark() le permitirá al compilador comprobar que cada subclase lo implementa. Si usa una enumeración y una gran switch, no se asegurará de que haya manejado todos los casos.

  2. Puede agregar nuevos casos (tipos de animales en su ejemplo). Esto se puede hacer a través de archivos fuente, e incluso a través de los límites del paquete. Con una enumeración, una vez que la has declarado, está congelada. La extensión abierta es una de las principales fortalezas de OOP.

Es importante tener en cuenta que el ejemplo de su colega no está en directa oposición al suyo.Si él quiere tipo de un animal para ser una propiedad expuesta (que es útil para algunas cosas), todavía se puede hacer eso sin necesidad de utilizar una enumeración, mediante el type object pattern:

public abstract class AnimalType { 
    public static AnimalType Unknown { get; private set; } 
    public static AnimalType Cat { get; private set; } 
    public static AnimalType Dog { get; private set; } 

    static AnimalType() { 
     Unknown = new AnimalType("Unknown"); 
     Cat = new AnimalType("Cat"); 
     Dog = new AnimalType("Dog"); 
    } 
} 

public class Animal { 
    public AnimalType Type { get; set; } 
} 

Esto le da la conveniencia de una enumeración: Puedes hacer AnimalType.Cat y puedes obtener el tipo de animal. Pero también le ofrece la flexibilidad de las clases: puede agregar campos al AnimalType para almacenar datos adicionales con cada tipo, agregar métodos virtuales, etc. Más importante aún, puede definir nuevos tipos de animales simplemente creando nuevas instancias de AnimalType.

7

Me animo a que reconsidere: en un anemic domain model (por los comentarios anteriores), los gatos no se comportan de manera diferente que perros, así que no hay polimorfismo. El tipo de animal realmente es solo un atributo. Es difícil ver qué herencia te compra allí.

+2

Gracias ... "los gatos no se comportan de forma diferente a los perros, por lo que no hay polimorfismo". parece ser un muy buen razonamiento. – Lijo

+3

Sin embargo, los gatos no ladran ... –

1

Ambas soluciones son correctas. Debería ver qué técnicas se aplican mejor a su problema.

Si su programa usa pocos objetos diferentes y no agrega clases nuevas, es mejor quedarse con las enumeraciones.

Pero si el programa utiliza una gran cantidad de objetos diferentes (diferentes clases) y puede agregar nuevas clases, en el futuro, mejor intente la forma de herencia.

5

Tener una enumeración es como organizar una fiesta para todos esos Open/Closed Principle is for suckers personas.

Realmente lo invita a verificar si un animal es de cierto tipo y luego aplicar una lógica personalizada para cada tipo. Y eso puede generar un código horrible que hace que sea muy difícil continuar construyendo en su sistema.

+0

+1 por sarcasmo. –

Cuestiones relacionadas