2011-06-07 13 views
5

Estoy creando una clase relativamente simple (por ejemplo, Persona) para una aplicación ASP.NET que tiene varias propiedades booleanas relacionadas (por ejemplo, Certificaciones). Tengo la opción de almacenarlas como múltiples propiedades:Cuándo usar colecciones frente a propiedades múltiples

Class Person 
    Property HasCertL1 
    Property HasCertL2 
    Property HasCertL3 
End Class 

O usando una colección y enumeración:

Enum Cert 
    L1 
    L2 
    L3 
End Enum 

Class Person 
    Property Certs as List(Of Cert) 
End Class 

La clase no se utiliza en otros lugares, y los artículos (CERT) será no sea actualizado sin volver a compilar la clase de todos modos. Estoy buscando razones para elegir una sobre la otra. ¿Alguien puede ofrecer alguna de las mejores prácticas o señalarme algunos recursos que cubren esto que me puedo haber perdido? ¡Gracias por adelantado!

Cheers, JE

Respuesta

3

Mi voto es para usar una colección.He aquí por qué: cuando configuras la clase con una propiedad para cada nivel de certificación, si agregas un nivel de certificación, deberías agregar un código adicional para verificar que las personas tuvieran ese nivel adicional. Eso requiere, posiblemente, un cambio en cualquier otra clase que use Person.

Si usa una lista, la clase Persona no cambia; solo hay un cambio en los valores disponibles para la lista. Eso requiere muchos menos cambios de código para verificar un determinado nivel de certificación.

+0

Este fue mi instinto, sin embargo, me resultó más difícil implementar b/c Tengo un formulario con casillas de verificación, por lo que Person.HasCertL1 = CertL1Box.Checked fue más limpio que si Cert1Box.Checked Then Person.Certs.Add (Certs.CertL1) , especialmente cuando intentas eliminarlos. Voy a utilizar tus sugerencias de todos modos, ¡nunca se sabe cuándo querrás reutilizar algo! :) –

+0

Las alegrías del diseño de software; nunca podrá escribir código que esté completamente desacoplado de sus dependencias y dependientes. Lo que puede hacer es enfocarse en ciertas situaciones en las que el código podría cambiar y asegurarse de que el código externo requiera un mínimo o ningún cambio en esas situaciones. – KeithS

2

creo que siempre es un buen método para mantener un ojo en posibilidad de ampliación de sus aplicaciones. Con eso en mente, elegiría el enfoque de recolección. Sin embargo, su pregunta no aclara si solo hay tres certificaciones o si hay más.

Estás hablando solo de actualizar certificaciones con recompilación en ese caso parece que hay opciones para la extensión.

+0

+1 para la respuesta correcta. Se lo di a @KeithS por incluir una explicación de cómo afectaría a otras clases. –

1

¿Por qué necesita una "colección y una enumeración"? ¿Cuál es el problema con el uso de una enumeración Bit Field con el atributo "Flags" para almacenar qué "Certs" tiene una "Persona"? Esto es en realidad una versión mucho más limpio de la opción 1.

por su comentario, aquí es un ejemplo muy trivial de lo que estoy hablando:


class Person 
{ 
    public string Name; 
    public Certifications Certifications; 
} 

[Flags] 
enum Certifications : int 
{ 
    A = 1, 
    B = 2, 
    C = 4, 
    D = 8, 
    E = 16, 
    F = 32, 
    G = 64, 
    H = 128, 
    I = 256 
}; 

static void Main() 
{ 
    Person a = new Person() { Name = "rob", Certifications = Certifications.A | Certifications.D | Certifications.G }; 
    Person b = new Person() { Name = "jeb", Certifications = Certifications.B | Certifications.C | Certifications.I }; 

    // Easy way using [Flags] ToString() override. 
    DisplayPerson(a); 
    DisplayPerson(b); 

    Console.WriteLine(); 

    // Traditional Way 
    DisplayPersonInfo(a); 
    DisplayPersonInfo(b); 
} 

static IEnumerable<string> GetCerts(Person person) 
{ 
    foreach(Certifications cert in Enum.GetValues(typeof(Certifications))) 
    { 
     if(PersonHasCert(person, cert)) 
      yield return (Enum.GetName(typeof(Certifications), cert)); 
    } 
} 

static bool PersonHasCert(Person person, Certifications cert) 
{ 
    return ((cert & person.Certifications) == cert); 
} 

static void DisplayPersonInfo(Person p) 
{ 
    Console.WriteLine 
    (
     String.Format 
     (
      "Name: {0}, Certifications: {1}", 
      p.Name, 
      String.Join(", ", GetCerts(p)) 
     ) 
    ); 
} 

static void DisplayPerson(Person p) 
{ 
    Console.WriteLine 
    (
     String.Format 
     (
      "Name: {0}, Certifications: {1}", 
      p.Name, 
      p.Certifications 
     ) 
    ); 
} 

Salida:

Nombre: rob, Certificados: A, D, G
Nombre: jeb, certificaciones: B, C, I

Nombre: robo, Certificaciones: A, D, G
Nombre: jeb, Certificaciones: B, C, I

la mencionada "[Banderas]" atributo de ayuda al compilador sé lo que estás utilizando esta estructura de datos para y mostrar los valores que contiene (utilizando el método ToString() en un "Enum" con el atributo, por lo que no tiene que iterar el Enum y hacer una prueba de bits para cada valor cuando desea mostrar todo el valores).

¿Cuáles son sus otras reservas sobre el uso de este enfoque? Parece ajustarse exactamente a lo que quieres lograr de manera muy eficiente y limpia.

this es un artículo bastante bueno sobre el tema.

Edición 2:

Código de ejemplo actualizado para incluir programa de ejemplo completo con las dos maneras de conseguir esta funcionalidad y algunos métodos de ayuda que usted debe ser capaz de utilizar en su aplicación.

+0

@Jens ver actualizaciones. –

+0

Guau, no me di cuenta de que el atributo de banderas lo hizo tan fácil. Definitivamente voy a intentar esto! gracias Brandon. –

+0

Ciertamente veo los beneficios de usar campos de bits, pero todavía no puedo entender cómo escribir un ciclo For Each limpio con esto. Entiendo cómo funciona el ejemplo que muestra, pero ¿qué ocurre si quiero hacer algo más que imprimir (por ejemplo, para cada certificado en certificados, certificado, validar, certificado siguiente)? ¿Tienes algún ejemplo de cómo podría hacer esto? ¡Gracias de nuevo! –

1

Mi opinión es que depende absolutamente de cómo vas a trabajar con esas propiedades. Para cualquier caso de uso, generalmente puede decir si es más conveniente trabajar con un objeto como una colección o como un conjunto de varias propiedades. Esto debería guiar su elección, aunque no es tan difícil convertir varias propiedades en colección o dividir la colección en artículos.

su situación (se sabe que tiene Cert1, Cert2 y Cert3 y nada más importa) es bastante raro en comparación con los casos en que nadie sabe cuántos elementos podría una colección tener, por lo que la mayor parte de las veces y haber limitado número de propiedades es no es una opción. En tu caso, podría ser una opción. Las propiedades separadas pueden permitirle almacenar objetos de una manera más fuertemente tipada.

Si no sabe qué opción elegir, le aconsejo que elija ambas. Implemente una clase Person que tendrá tanto propiedad de colección como propiedad separada para cada artículo. La implementación interna no importa, solo la interfaz importa aquí. Entonces podrá usar cualquier cosa de otras clases y los usos probablemente harán que sea más claro cómo debería implementarse. Implementación de muestra (no implementa completamente la parte de recopilación ya que no puede agregarle ningún elemento):

class Person 
{ 
    public Cert1 Cert1 { get; set; } 
    public Cert2 Cert2 { get; set; } 
    public Cert3 Cert3 { get; set; } 

    public IEnumerable<Cert> AllCertificates 
    { 
     get 
     { 
      return new Cert[] {Cert1, Cert2, Cert3} 
         .Where(c => c != null) 
         .ToArray(); 
     } 
    } 
} 
+0

Me gusta esta idea y probablemente la use para proyectos más grandes en el futuro. –

Cuestiones relacionadas