oop - resueltos - modelo de dominio online
Herencia vs propiedades enum en el modelo de dominio (6)
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.
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.
Lo que me gustaría ver es esto:
class Animal {
}
class Cat : Animal {
}
class Dog : Animal {
}
Lo que el otro colega dice 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!
Así es como razono al respecto:
Solo use herencia si el rol / tipo nunca cambiará. p.ej
usando herencia para cosas como:
Bombero <- Empleado <- La persona está equivocada.
tan pronto como Freddy el bombero cambie de trabajo o quede desempleado, debes matarlo y recrear un nuevo objeto del nuevo tipo con todas las relaciones antiguas asociadas.
Entonces, 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, por ejemplo, si no necesita comportamientos muy complejos asociados con el rol / tipo.
La forma más correcta sería darle a la persona clase 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 excesivo:
freddy.CurrentEmployment = new Employement( employmentDate, jobTitle );
De esta manera, Freddy puede convertirse en un desarrollador sin 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 trabajo.
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, podría terminar con un modelo de datos overcomplex un poco 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 "if type == JobTitles.Fireman ..." 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 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. por ejemplo, para productos.
es posible que tenga CD <- Producto y Libro <- Producto. La herencia gana aquí porque en este caso es muy probable que tengas un estado diferente asociado con los tipos. El CD puede tener una cantidad de pistas de propiedad, mientras que un libro puede tener varias páginas de propiedad.
En resumen, depende ;-)
Además, al final del día probablemente termines con muchas declaraciones de cambio de cualquier manera. Digamos que quiere editar un "Producto", incluso si usa la herencia, probablemente tenga un código como este:
if (producto es Libro) Response.Redicted ("~ / EditBook.aspx? id" + product.id);
Debido a que la codificación de la url del libro de edición en la clase de entidad sería desagradable, ya que obligaría a su empresa a conocer la estructura de su sitio, etc.
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.
Los mensajes son buenos cuando:
- El conjunto de valores es fijo y nunca o muy raramente cambia.
- Desea poder representar una unión de valores (es decir, combinar indicadores).
- No necesita adjuntar otro estado a cada valor. (Java no tiene esta limitación).
Si pudieras resolver tu 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, es probable que las enumeraciones no sean la respuesta correcta. Usando clases polimórficas, puedes:
Estáticamente asegúrese de que se maneje todo el comportamiento específico del tipo. Por ejemplo, si necesita que todos los animales puedan
Bark()
, hacer clases deAnimal
con un método abstractoBark()
permitirá que el compilador compruebe que cada subclase lo implementa. Si usa una enumeración y un granswitch
, no se asegurará de que haya manejado todos los casos.Puede agregar casos nuevos (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 quiere que el tipo de un animal sea una propiedad expuesta (lo cual es útil para algunas cosas), puede hacerlo sin usar una enumeración, usando el patrón de tipo de objeto :
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 brinda la comodidad de una enumeración: puede hacer AnimalType.Cat
y puede obtener el tipo de animal. Pero también le da la flexibilidad de las 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
.
Te recomiendo que reconsideres: 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í.
Tener una enumeración es como organizar una fiesta para todos esos Open/Closed Principle is for suckers
gente Open/Closed Principle is for suckers
.
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.