2011-09-13 23 views
5

En [this post], estoy luchando por implementar un Patrón de estado como lo sugiere @jonp. No entiendo muy bien cómo usar lo que ha publicado, pero me lleva a pensar que tal vez estoy tratando de meter una clavija cuadrada en un agujero redondo. Así que mi pregunta:Modelado "Soy * pero también soy **"

Si tengo un visitante a mi sitio que puede desempeñar múltiples funciones es decir, un User podría ser una Vendor, un Employer, un Advertiser, o la totalidad de lo anterior, debo utilizar la herencia? He declarado:

class Vendor : User {} 
class Advertiser : User {} 

etcétera, pero cuando un usuario es a la vez un vendedor y un empleador a continuación ejemplos de diferentes clases realmente apuntan al mismo objeto subyacente ... No estoy seguro de que esto puede funcionar. ¿Cómo lo modelo?

* actualización *

gracias a todos (a todos obtiene un punto (que es todo lo que puedo dar)). He estado tirando de mi pelo sobre copias en profundidad con EF, downcasting y el patrón de estado de los últimos días. El enfoque de roles tiene mucho más sentido.

+2

Quizás pueda interesarte en C++, un lenguaje con herencia arbitraria? ;-) –

+0

@Kerrek C++ no proporciona mucha ayuda para crear dinámicamente un subtipo de usuario único que herede un conjunto dinámico de roles basado en lo que se lee de la base de datos. –

Respuesta

4

Esto suena como una situación a la cual el patrón de atributo (o lo que yo llamo) sería muy apropiado. Es un enfoque mucho más flexible que la herencia simple que se puede utilizar para especificar múltiples "comportamientos" o en su caso tipos de User. Realmente no es nada más complicado que un objeto que tenga etiquetas de otro tipo de objeto.

La forma más fácil de poner en práctica, sería tener una clase concreta User, con una propiedad de sólo lectura IList<UserRole> (internamente esto puede ser un campo List<T> tal vez). Su clase UserRole sería abstracta, y VendorRole/AdvertiserRole/etc. se derivaría de ello, lo que le permite etiquetar en un número determinado de roles diferentes (incluso los del mismo tipo) en un usuario determinado. Estos roles también pueden definir sus propios comportamientos personalizados, métodos de utilidad, etc.

Además, se podría definir un método GetRole<TRole> en su clase User para facilitar el acceso a las funciones de un tipo específico (suponiendo que cada User sólo tiene un único Role de un subtipo específico).

Nota al margen: también puede considerar el decorator patern, que está estrechamente relacionado con el patrón mencionado anteriormente, aunque personalmente creo que es excesivo aquí, y realmente no agrega nada en términos de flexibilidad o potencia. A menudo solo oscurece lo que estás tratando de hacer; aunque puedes investigar de todos modos.

+0

¿Es este un decorador? Me parece más como un escenario de colección polimórfica estándar de pantano, o posiblemente múltiples referencias 1: 0-1. –

+0

@Jeffrey: Tiene razón, no es exactamente el patrón de decorador, pero es un enfoque más sensato/simple que es igual de poderoso aquí. :-) – Noldorin

+0

Solo actualizo mi respuesta en realidad ... He notado que el patrón del decorador está claramente relacionado, pero un poco más involucrado. – Noldorin

3

Debe favorecer composición sobre la herencia si los diferentes roles tienen que contener lógica diferente que se implementa utilizando polimorfismo y métodos abstractos, por ejemplo:

public class User 
{ 
    public Role Role { get; set; } 
} 

public abstract class Role 
{ 
    abstract void DoRoleSpecificStuff(); 
} 

public class Vendor : Role 
{ 
    public void DoRoleSpecificStuff() 
    { 
     /* ... */ 
    } 
} 

public class Employer : Role 
{ 
    public void DoRoleSpecificStuff() 
    { 
     /* ... */ 
    } 
} 

public class Advertiser : Role 
{ 
    public void DoRoleSpecificStuff() 
    { 
     /* ... */ 
    } 
} 

Si un usuario puede tener múltiples funciones, considere el uso de una propiedad de colección Roles:

public IEnumerable<Role> Roles { get; set; } 

de lo contrario, un enumeración usando el atributo [Flags] podría estar bien, también, en función de si tiene que ser capaz de asignar múltiples roles:

public class User 
{ 
    public Roles Roles { get; set; } 
} 

[Flags] 
public enum Roles 
{ 
    Advertiser = 0x0, 
    Employer = 0x1, 
    Vendor = 0x2  
} 

Se podría asignar una combinación de diferentes funciones de la siguiente manera:

User user = new User 
{ 
    Roles = Roles.Advertiser | Roles.Vendor; 
}; 

Eso haría que el Usuario sea tanto un Anunciante como un Proveedor, pero no un Empleador.

+1

Um, no. El OP preguntó sobre casos en los que un usuario puede tener múltiples roles. –

+2

¿No podría tener User.Roles, Roes inEnumerable ? – Mathias

+0

@Jeffrey por favor revise su comentario. Estaba actualizando mi respuesta cuando escribiste. –

2

"Soy * pero también soy **" se conoce como Herencia Múltiple. C# no es compatible con esto, por lo que no debería considerarlo.

+4

Quizás, pero modelar el * concepto * sobre el que está preguntando no requiere MI. –

+0

bueno ... No sé. MI es útil para modelar hacia arriba, es decir, cuando un nodo en un árbol de taxonomía pertenece a múltiples raíces, sin embargo (podría estar equivocado), en mi caso, la herencia es lateral; en otras palabras, el empleado y el vendedor son en realidad hermanos en la taxonomía – ekkis

2

De hecho, es la composición por herencia, pero es más como esto si un solo usuario puede tener múltiples roles.

Si hay relativamente pocas funciones, un 'estacionamiento' análogo a un resultado de combinación externa puede funcionar. En este patrón, no se requiere clase base Role.

class User 
{ 
    // all of these may be null if not applicable 
    VendorRole VendorRole { get; set; } 
    EmployeeRole EmployeeRole { get; set; } 
    AdvertiserRole AdvertiserRole { get; set; } 
} 

Si un usuario puede tener múltiples instancias de una sola función, una colección aparece:

class User 
{ 
    // all of these may be null if not applicable 
    VendorRole VendorRole { get; set; } 
    EmployeeRole EmployeeRole { get; set; } 
    ICollection<AdvertiserRole> AdvertiserRoles { get; } 
} 

Alternativamente, si puede haber un montón desordenado de los roles, si los papeles se añaden dinámicamente, o qué tienes, necesitarás una colección y un tipo de base. Si Entity Framework está involucrado, sin embargo, los roles añadidos dinámicamente me parecen poco probables.

class User 
{ 
    ICollection<Role> Roles; 
} 
Cuestiones relacionadas