Когда использовать коллекции против нескольких свойств - PullRequest
5 голосов
/ 07 июня 2011

Я создаю относительно простой класс (например, Person) для приложения ASP.NET, который имеет несколько связанных логических свойств (например, сертификаты).У меня есть возможность сохранить их как несколько свойств:

Class Person
    Property HasCertL1
    Property HasCertL2
    Property HasCertL3
End Class

Или использовать коллекцию и перечисление:

Enum Cert
    L1
    L2
    L3
End Enum

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

Класс не будет использоваться в другом месте, а элементы (сертификаты)не будет обновляться без перекомпиляции класса в любом случае.Я ищу причины для выбора одного над другим.Может кто-нибудь предложить какие-либо передовые практики или указать мне некоторые ресурсы, которые покрывают это, что я, возможно, пропустил?Заранее спасибо!

Ура, JE

Ответы [ 4 ]

3 голосов
/ 07 июня 2011

Мой голос - использовать коллекцию.И вот почему: когда вы устанавливаете класс со свойством для каждого уровня сертификации, если вы хотите добавить уровень сертификации, вам нужно будет добавить дополнительный код, чтобы проверить, что у людей есть этот дополнительный уровень.Это требует, возможно, изменения для любого другого класса, который использует Person.

Если вы используете список, класс Person не изменяется;есть просто изменение доступных значений для списка.Это требует гораздо меньше изменений кода для проверки на определенный уровень сертификации.

2 голосов
/ 07 июня 2011

Я думаю, что всегда полезно следить за расширяемостью ваших приложений.Имея это в виду, я бы пошел на коллекционный подход.Однако из вашего вопроса не ясно, есть ли только три сертификата или их больше.

Вы говорите только об обновлении сертификатов с перекомпиляцией, в этом случае кажется, что есть варианты для расширения.

1 голос
/ 07 июня 2011

Мое мнение таково, что это абсолютно зависит от того, как вы собираетесь работать с этими свойствами.Для любого случая использования обычно можно сказать, удобнее ли работать с объектом как коллекцией или набором нескольких свойств.Это должно сделать ваш выбор, хотя не так сложно преобразовать несколько свойств в коллекцию или разделить коллекцию обратно на элементы.

Ваша ситуация (вы знаете, что у вас есть Cert1, Cert2 и Cert3 и ничего больше не имеет значения) довольно редка по сравнению со случаями, когда никто не знает, сколько предметов может иметь коллекция, поэтомувремена, имеющие ограниченное количество свойств, не вариант.В вашем случае это может быть вариант.Отдельные свойства могут позволить вам хранить объекты более строго типизированным способом.

Если вы не знаете, какой вариант выбрать, я бы посоветовал выбрать оба варианта.Реализуйте класс Person, который будет иметь как свойство коллекции, так и отдельное свойство для каждого элемента.Внутренняя реализация не имеет значения, здесь важен только интерфейс.Тогда вы сможете использовать что-либо из других классов, и использование, вероятно, сделает более понятным, как это должно быть реализовано.Пример реализации (он не полностью реализует часть коллекции, так как вы не можете добавить элемент к нему):

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();
        }
    }
}
1 голос
/ 07 июня 2011

Зачем вам нужна «коллекция и перечисление»? В чем проблема с использованием перечисления Bit Field с атрибутом " Flags " для хранения того, что "Certs" имеет "Person"? Это на самом деле просто более чистая версия варианта 1.

На ваш комментарий, вот очень банальный пример того, о чем я говорю:


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
        )
    );
}

Выход:

Наименование: граб, Сертификаты: A, D, G
Имя: Джеб, Сертификаты: B, C, I

Наименование: граб, Сертификаты: A, D, G
Имя: Джеб, Сертификаты: B, C, I

Вышеупомянутый атрибут «[Flags]» помогает компилятору знать, для чего вы используете эту структуру данных и отображать содержащиеся в ней значения (используя метод ToString () для «Enum» с атрибутом, так что вы не необходимо выполнить итерации Enum и выполнить побитовый тест для каждого значения, когда вы хотите отобразить все значения).

Какие у вас другие оговорки по поводу использования этого подхода? Похоже, что это именно то, что вы хотите достичь, очень эффективно и чисто.

это довольно хорошая статья, освещающая эту тему.

Редактировать 2:

Обновлен пример кода, включающий полный пример программы, использующей оба способа достижения этой функциональности и некоторые вспомогательные методы, которые вы сможете использовать в своем приложении.

...