Pregunta

¿Qué diseño de clase es mejor y por qué?

public class User
{
    public String UserName;
    public String Password;
    public String FirstName;
    public String LastName;
}

public class Employee : User
{
    public String EmployeeId;
    public String EmployeeCode;
    public String DepartmentId;
}

public class Member : User
{
    public String MemberId;
    public String JoinDate;
    public String ExpiryDate;
}

O

public class User
{
    public String UserId;
    public String UserName;
    public String Password;
    public String FirstName;
    public String LastName;
}

public class Employee
{
    public User UserInfo;
    public String EmployeeId;
    public String EmployeeCode;
    public String DepartmentId;
}

public class Member
{
    public User UserInfo;
    public String MemberId;
    public String JoinDate;
    public String ExpiryDate;
}
¿Fue útil?

Solución

La pregunta se responde simplemente reconociendo que la herencia modela una relación "ES-A", mientras que la membresía modela una relación "TIENE-A".

  • Un empleado ES un usuario
  • Un empleado TIENE una información de usuario

¿Cuál es correcto?Esta es tu respuesta.

Otros consejos

No me gusta ninguno de los dos.¿Qué sucede cuando alguien es a la vez miembro y empleado?

Pregúntese lo siguiente:

  • ¿Quieres modelar un empleado? ES ¿un usuario?Si es así, elija herencia.
  • ¿Quieres modelar un empleado? TIENE ¿Información del usuario?Si es así, use composición.
  • ¿Están involucradas funciones virtuales entre el Usuario (info) y el Empleado?Si es así, utilice la herencia.
  • ¿Puede un empleado tener varias instancias de Usuario (información)?Si es así, use composición.
  • ¿Tiene sentido asignar un objeto Empleado a un objeto Usuario (información)?Si es así, utilice la herencia.

En general, esfuércese por modelar la realidad que simula su programa, bajo las limitaciones de la complejidad del código y la eficiencia requerida.

No creo que la composición sea siempre mejor que la herencia (normalmente).Si el Empleado y el Miembro realmente son Usuarios y se excluyen mutuamente, entonces el primer diseño es mejor.Considere el escenario en el que necesita acceder al nombre de usuario de un empleado.Usando el segundo diseño tendrías:

myEmployee.UserInfo.UserName

lo cual es malo (ley de Demeter), por lo que refactorizarías a:

myEmployee.UserName

lo que requiere un pequeño método en Empleado para delegar al objeto Usuario.Todo lo cual se evita con el primer diseño.

Buena pregunta, aunque para evitar distracciones sobre bien y equivocado Consideraría preguntar los pros y los contras de cada enfoque; creo que eso es lo que quiso decir con cuál es mejor o peor y por qué.De todos modos ....

El primer enfoque, también conocido como herencia

Ventajas:

  • Permite comportamiento polimórfico.
  • Es inicialmente sencillo y conveniente.

Contras:

  • Puede volverse complejo o torpe con el tiempo si Se agregan más comportamientos y relaciones.

El segundo enfoque, también conocido como composición

Ventajas:

  • Se asigna bien a escenarios que no son de programación orientada a objetos, como tablas relacionales, programación estructurada, etc.
  • Es sencillo (aunque no necesariamente conveniente) incrementalmente ampliar las relaciones y el comportamiento.

Contras:

  • No hay polimorfismo, por lo tanto, es menos conveniente utilizar información y comportamiento relacionados.

Listas como estas + las preguntas Jon Limjap mencionado lo ayudará a tomar decisiones y comenzar; luego podrá encontrar lo que bien las respuestas deberían haber sido ;-)

También puedes pensar en el Empleado como un role del Usuario (Persona).El rol de un Usuario puede cambiar con el tiempo (el usuario puede quedar desempleado) o el Usuario puede tener múltiples roles al mismo tiempo.

La herencia es mucho mejor cuando hay real "es una" relación, por ejemplo manzana - fruta.Pero mucho cuidado:Círculo: la elipse no es una relación real "es una", porque el círculo tiene menos "libertad" que la elipse (el círculo es una estado de elipse) - ver: Problema de elipse circular.

Las verdaderas preguntas son:

  • ¿Cuáles son las reglas comerciales y las historias de usuario detrás de un usuario?
  • ¿Cuáles son las reglas comerciales y las historias de usuario detrás de un empleado?
  • ¿Cuáles son las reglas comerciales y las historias de usuario detrás de un miembro?

Pueden ser tres entidades completamente ajenas o no, y eso determinará si su primer o segundo diseño funcionará, o si es necesario otro diseño completamente diferente.

Ninguno de los dos es bueno.Demasiado estado mutable.No debería poder construir una instancia de una clase que se encuentre en un estado no válido o parcialmente inicializado.

Dicho esto, el segundo es mejor porque favorece la composición sobre la herencia.

Declarar sus requisitos/especificaciones podría ayudar a llegar al "mejor diseño".
Su pregunta está demasiado "sujeta a la interpretación del lector" en este momento.

Aquí hay un escenario en el que deberías pensar:

La composición (el segundo ejemplo) es preferible si el mismo Usuario puede ser tanto Empleado como Miembro.¿Por qué?Porque para dos instancias (Empleado y Miembro) que representan al mismo Usuario, si los datos del Usuario cambian, no es necesario actualizarlos en dos lugares.Sólo la instancia de Usuario contiene toda la información del Usuario y solo ésta debe actualizarse.Dado que las clases Empleado y Miembro contienen la misma instancia de Usuario, ambas contendrán automáticamente la información actualizada.

Tres opciones más:

  1. Tener el User La clase contiene información complementaria tanto para empleados como para miembros, con los campos no utilizados en blanco (el ID de un particular User indicaría si el usuario era empleado, miembro, ambos o lo que sea).

  2. Tener un User clase que contiene una referencia a una ISupplementalInfo, dónde ISupplementalInfo es heredado por ISupplementalEmployeeInfo, ISupplementalMemberInfo, etc.Código que es aplicable a todos los usuarios con el que podría trabajar. User objetos de clase y código que tenía un User referencia podría obtener acceso a la información complementaria de un usuario, pero este enfoque evitaría tener que cambiar User si en el futuro se requieren diferentes combinaciones de información complementaria.

  3. Como arriba, pero tiene el User clase contiene algún tipo de colección de ISupplementalInfo.Este enfoque tendría la ventaja de facilitar la adición de propiedades en tiempo de ejecución a un usuario (p. ej.Porque un Member fue contratado).Al utilizar el enfoque anterior, habría que definir diferentes clases para diferentes combinaciones de propiedades;convertir un "miembro" en un "miembro+cliente" requeriría un código diferente al de convertir un "empleado" en un "empleado+cliente".La desventaja de este último enfoque es que haría más difícil protegerse contra atributos redundantes o inconsistentes (usar algo como un Dictionary<Type, ISupplementalInfo> contener información complementaria podría funcionar, pero parecería un poco "voluminoso").

Yo tendería a favorecer el segundo enfoque, ya que permite una expansión futura mejor que la herencia directa.Trabajar con una colección de objetos en lugar de un solo objeto puede resultar un poco engorroso, pero ese enfoque puede ser más capaz que otros de manejar los requisitos cambiantes.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top