Herencia vs propiedades de enumeración en el modelo de dominio


Tuve una discusión en el trabajo sobre "La herencia en el modelo de dominio está complicando la vida de los desarrolladores". Soy un programador de OO, así que empecé a buscar argumentos que tener herencia en el modelo de dominio facilitará la vida del desarrollador en realidad en lugar de tener interruptores por todas partes.

Lo que me gustaría ver es esto :

class Animal {

}

class Cat : Animal {

}

class Dog : Animal {

}

Lo que el otro colega está diciendo es:

public enum AnimalType {
    Unknown,
    Cat,
    Dog
}

public class Animal {

    public AnimalType Type { get; set; }

}

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

Gracias!

Author: Daniel Severin, 2010-11-23

6 answers

Así es como razono al respecto:

Solo use herencia si el rol/tipo nunca cambiará. por ejemplo,

Usando la herencia para cosas como:

Bombero

Tan pronto como Freddy el bombero cambia de trabajo o se queda desempleado, tienes que matarlo y recrear un nuevo objeto del nuevo tipo con todas las viejas relaciones asociadas a él.

Así que la solución ingenua al problema anterior sería dar una propiedad JobTitle enum a la clase de persona. Esto puede ser suficiente en algunos escenarios, por ejemplo, si no necesita comportamientos muy complejos asociados con el rol/tipo.

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

Por ejemplo

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

O si eso es exagerado:

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

De esta manera , Freddy puede convertirse en un desarrollador sin que tengamos 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 jobtitle.

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 O/R mapping, podría terminar con un modelo de datos un poco complejo entre bastidores si el mapeador intenta mapear cada subtipo a una nueva tabla. Así que en tales casos, a menudo voy para el enfoque enum si no hay un comportamiento real / complejo asociado con los tipos. Puedo vivir con un " if type = = JobTitles.Bombero ..."si el uso es limitado y hace las cosas más fáciles o menos complejas.

Por ejemplo, el diseñador de Entity Framework 4 para. NET solo puede asignar cada subtipo a una nueva tabla. y puede obtener un modelo feo o un montón de uniones cuando consulta su base de datos sin ningún beneficio real.

Sin embargo, uso herencia si el tipo/rol es estático. por ejemplo, para productos.

Es posible que tenga CD

Así que en resumen, depende; -)

Además, al final del día lo más probable es que termine con una gran cantidad de instrucciones de cambio de cualquier manera. Digamos que desea editar un "Producto", incluso si utiliza herencia, probablemente tendrá un código como este:

Si (el producto es libro) Respuesta.Redicted ("~/EditBook.aspx?id " + product.id);

Porque codifica el libro de edición url en la clase entity sería simplemente feo ya que obligaría a sus entidades de negocio a saber sobre la estructura de su sitio, etc.

 25
Author: Roger Johansson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-23 10:14:07

Les insto a reconsiderar: en un modelo de dominio anémico (según los comentarios anteriores), los gatos no se comportan de manera diferente a los perros, por lo que no hay polimorfismo. El tipo de animal realmente es solo un atributo. Es difícil ver qué herencia te compra allí.

 7
Author: Jeff Sternal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-23 17:38:35

Los enums son buenos cuando:

  1. El conjunto de valores es fijo y nunca o muy raramente cambia.
  2. Desea ser capaz de representar una unión de valores (es decir, combinar banderas).
  3. No es necesario añadir otro estado a cada valor. (Java no tiene esta limitación.)

Si pudiera resolver su problema con un número, una enumeración es probablemente un buen ajuste y más seguro de tipo. Si necesita más flexibilidad que la anterior, entonces es probable que no la respuesta correcta. Usando clases polimórficas, usted puede:

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

  2. Puede agregar nuevos casos (tipos de animales en su ejemplo). Esto puede ser hecho a través de archivos de origen, e incluso a través de los límites de paquetes. Con una enumeración, una vez que lo has declarado, se congela. La extensión abierta es una de las principales fortalezas de la POO.

Es importante tener en cuenta que el ejemplo de su colega no está en oposición directa con el suyo. Si quiere que el tipo de un animal sea una propiedad expuesta (lo cual es útil para algunas cosas), aún puede hacerlo sin usar una enumeración, usando el patrón de objeto de tipo :

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 da la conveniencia de una enumeración: usted puede hacer AnimalType.Cat y usted puede conseguir el tipo de un animal. Pero también le da la flexibilidad de clases: puede agregar campos a 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.

 6
Author: munificent,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-23 17:17:32

Tener una enumeración es como hacer una fiesta para todas esas Open/Closed Principle is for suckers personas.

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

 5
Author: jgauffin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-09 07:59:16

Lo más importante es que OOPS significa modelar la realidad. La herencia te da la oportunidad de decir que el gato es un animal. El animal no debe saber si es un gato ahora gritarlo y luego decidir que se supone que debe maullar y no Ladrar, la encapsulación se derrota allí. Menos código como ahora usted no tiene que hacer si otra cosa como usted dijo.

 1
Author: Jinesh Parekh,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-23 09:56:19

Ambas soluciones son correctas. Usted debe mirar qué técnicas se aplica mejor a usted problema.

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

Pero si programa usa muchos objetos diferentes (clases diferentes), y puede agregar nuevas clases, en el futuro, mejor intente la forma de herencia.

 1
Author: umlcat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-14 15:36:19