Моделирование "Я *, но я также **" - PullRequest
5 голосов
/ 13 сентября 2011

В [ этом посте ] я изо всех сил пытаюсь реализовать шаблон состояний, как подсказывает @jonp. Я не совсем понимаю, как использовать то, что он написал, но это наводит на мысль, что, может быть, я пытаюсь вставить квадратный колышек в круглое отверстие. Итак, мой вопрос:

Если у меня есть посетитель моего сайта, который может играть несколько ролей, то есть User может быть Vendor, Employer, Advertiser ИЛИ всем вышеперечисленным, следует ли мне использовать наследование? Я объявил:

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

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

* обновление *

спасибо всем (вы все получаете точку (это все, что я могу дать)). В последние несколько дней я вырывал свои волосы поверх глубоких копий с помощью EF, подавления и модели состояния. Ролевый подход имеет гораздо больше смысла.

Ответы [ 4 ]

4 голосов
/ 13 сентября 2011

Это похоже на ситуацию, в которой шаблон атрибута (или я так его называю) был бы очень уместным.Это гораздо более слабосвязанный подход, чем простое наследование, которое можно использовать для указания нескольких «поведений» или в вашем случае видов User.Это на самом деле ничего сложнее, чем объект, имеющий теги другого типа объекта.

Самый простой способ реализовать его - это иметь конкретный класс User со свойством только для чтения IList<UserRole> (внутренне).это может быть List<T> поле, возможно).Ваш класс UserRole будет абстрактным, а VendorRole / AdvertiserRole / etc.будет происходить из него, позволяя вам пометить произвольное количество различных ролей (даже одного и того же типа) для данного пользователя.Кроме того, эти роли могут определять свои собственные пользовательские поведения, служебные методы и т. Д.

Кроме того, вы можете определить метод GetRole<TRole> в своем классе User, чтобы облегчить доступ к ролям определенного типа (при условии, чтокаждый User имеет только один Role определенного подтипа).

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

3 голосов
/ 13 сентября 2011

Вы должны отдать предпочтение Композиция над наследованием , если разные роли должны содержать разную логику, которая будет реализована с использованием полиморфизма и абстрактных методов, например:

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()
    {
        /* ... */
    }
}

Если пользователь можетиметь несколько ролей, рассмотрите возможность использования свойства коллекции Roles:

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

В противном случае перечисление с использованием атрибута [Flags] может также подойти, в зависимости от того, требуется ли вамчтобы иметь возможность назначать несколько ролей:

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

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

Вы можете назначить комбинацию различных ролей следующим образом:

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

Это сделает пользователя и рекламодателем, и продавцом, ноне работодатель.

2 голосов
/ 13 сентября 2011

Это действительно композиция, а не наследование, но это скорее так, если один пользователь может иметь несколько ролей.

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

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

Если у пользователя может быть несколько экземпляров одной роли, всплывает коллекция:

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

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

class User
{
    ICollection<Role> Roles;
}
2 голосов
/ 13 сентября 2011

«Я *, но я тоже **» называется множественным наследованием.C # не поддерживает это, поэтому вы не должны об этом думать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...