Хорошая схема проектирования для реализации различных видов поведения по предмету

Каков наилучший дизайн для этого сценария?
У меня разные типы объектов: User, Channel, MessageBox, UserGroup и т.д.
User и Channel могут иметь разрешение на другие объекты. Например, User имеет следующее перечисление, определенное как его разрешения для MessageBox:

CanRead,
CanWrite,
CanDelete,
...

Другие перечисления определены для User как владелец других типов объектов.

Кроме того, Channel имеет разные значения enum для этих объектов. Например, рассмотрите Channel как владельца и MessageBox как объект:

CanDispath
CanRetrieve
...

Все разрешения сохраняются и извлекаются из конкретной таблицы в базе данных с использованием поразрядного сравнения:

OwnerID........OwnerType........ObjectID........ObjectType........AccessLevel  
  1              User              10           MessageBox            38     
  5             Channel            12           MessageBox            18  

Теперь в коде позади, Какой лучший способ реализовать классы разрешений?

1- Определить классы PermissionManager, UserPermissionManager, ChannelPermissionManager отдельно друг от друга. Другие классы просто вызывают PermissionManager как:

if (new PermissionManager.HasAccess(CurrentUser,  
                                    CurrentMessageBox, 
                                    UserPermissions.CanReadMessages))  

Затем PermissionManager определяет, к какому классу относится это на основе OwnerType (UserPermissionManager или ChannelPermissionManager), и вызывает его метод HasAccess. Таким образом, PermissionManager.HasAccess всегда вызывается, и я думаю, что он может сделать код более удобным и расширяемым. Это мое предпочтительное решение, но поскольку PermissionManager, UserPermissionManager и ChannelPermissionManager относятся к одному и тому же контексту, я думаю, что должна быть иерархия или, возможно, интерфейс, чтобы эти 3 класса стали более интегрированными. Но я не знаю, как связать их вместе.

2- Определите интерфейс IPermissionManager и внесите в него UserPermissionManager и ChannelPermissionManager. Добавьте PermissionManagerTypes перечисление. Создайте класс factory и вызовите Менеджеры, например:

IPermissionManager UserManager =   
    PermissionFactory.Create(PermissionsManagerTypes.User);
if (UserManager.HasAccess(CurrentUser,  
                          CurrentMessageBox, 
                          UserPermissions.CanReadMessages))  

Это своего рода неудачная попытка связать классы вместе. Но я подумал, что было бы неплохо упомянуть об этом здесь, чтобы вы знали, чего я пытаюсь достичь.

P.S. Я не могу определить классы как статические, так как они должны иметь приватную переменную типа ObjectContext (Entity Framework).

Есть ли лучшее решение для достижения этого?
Спасибо и извиняюсь за очень длительный вопрос.

Ответ 1

Ну, это довольно сложно ответить. Вы можете попытаться создать базовый интерфейс IPermission;

interface IPermission<TOwner>
{
}

Затем вы реализуете этот интерфейс для типов, которые вы хотите иметь для разрешения.

class UserPermission : IPermission<User>
{
    public UserPermission(CustomerPermissionType type)
    {
        // Store the type
    }
}

class ChannelPermission : IPermission<Channel>
{
    public ChannelPermission (ChannelPermissionType type)
    {
        // Store the type
    }
}

Теперь вам нужен интерфейс, который предоставляет разрешения для определенных объектов.

interface IPermissionProvider
{
    bool HasPermission<TOwner>(IPermission<TOwner> permission, TOwner owner, object target);
}

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

class PermissionDispatcher : IPermissionProvider
{
    public void RegisterPermissionProvider<TOwner>(IPermissionProvider     permissionProvider)
    {
        // Store it somewhere
    }

    public IPermissionProvider GetPermissionProvider<TOwner>()
    {
        // Look up a permission provider that is registered for the specified type TOwner and return it.
    }

    bool IPermissionProvider.HasPermission<TOwner>(IPermission<TOwner> permission,     TOwner owner, object target)
    {
        IPermissionProvider  permissionProvider = GetPermissionProvider<TOwner>();
        return permissionProvider .HasPermission<TOwner>(permission, owner, target);
    }
}

Последний шаг должен был бы создать конкретные реализации IPermissionProvider для пользователя и канала и зарегистрировать их в PermissionDispatcher при запуске вашего приложения/службы.

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

void foo()
{
    IPermissionProvider permissionProvider = ... the dispatcher, could be a singleton ...;
    User user = ...;
    MessageBox messageBox = ...;
    UserPermission userCanReadPermission = new UserPermission(UserPermissionType.CanRead);
    bool hasUserCanReadPermission = permissionProvider.HasPermission(userCanReadPermission, user, messageBox);

}

Что-то вроде этого будет единственным способом решить эту проблему, не принимая зависимость от обработки разрешений в ваших типах доменов. Тем не менее я абсолютно уверен, что это не идеальное решение.

Ответ 2

Я вообще не думал об этом, но:

interface HasPermissions {
   getPermissionsFor(object)
}

User implements HasPermissions

Channel implements HasPermissions

etc..


User user = new User();

if user.getPermissionsFor(object).contains(canRead)