Как смоделировать это в DDD и шаблон хранилища - PullRequest
3 голосов
/ 16 февраля 2012

Я хочу смоделировать сервис, подобный этому

public class FooService
{
    public GetById(ISecurityContext context, id)
    {
        //checking context has right to view
        //calling Foo repository to getById
    }

    public Add(ISecurityContext context,Foo fooEntity)
    {
        //checking context has right to add
        //calling Foo repository to add
    }



}

В вышеупомянутых методах я хочу передать другой тип SecurityContext. То, что я сделал, это

Public Interface ISecurityContext
{

}

UsernamePasswordContext : ISecurityContext
{
   public string Username { get; set; }
   public string Password { get;set; }

}

SessionContext : ISecurityContext
{
   public string SessionId {get ; set;}
}

Итак, в моей учетной записиСлужба У меня есть метод

public class AccountService
{
    public Account GetAccountFromSecurityContext(ISecurityContext context)
    {
        if(context is UsernamePasswordContext)
            return GetAccountByUsernamePassword(context.Username,context.Password);
        else if (context is SessionContext)
            return GetAccountBySessionId(context.SessionId);

        // more else if for different type of context
    }


}

В приведенном выше коде мне не понравилось так много, если еще Так что я попытался ввести полиморфизм

Так что в моем интерфейсе ISecurityContext я добавил метод GetAccount, который все подклассбудет реализовывать

Public Interface ISecurityContext
{
     Account GetAccount();
}


UsernamePasswordContext : ISecurityContext
{
   public string Username { get; set; }
   public string Password { get;set; }

   public Account GetAccount()
   {
       //call account service 
       GetAccountByUsernamePassword(this.Username,this.Password);
   }


}

и моя учетная запись станет такой

public class AccountService
{
    public Account GetAccountFromSecurityContext(ISecurityContext context)
    {
       context.GetAccount();
    }   

}

Но проблема здесь в том, что я вызываю службу / хранилище из моего UsernamePasswordContext POCO, который уничтожает DDD

Так как же я могу смоделировать этот сценарий?

1 Ответ

1 голос
/ 16 октября 2012

Я думаю, что вы недалеко от решения.В этом случае я бы ввел фабрику в ваш AccountService, который взял бы на себя ответственность if..then..else.Тогда завод мог бы использовать одно из многих возможных решений.

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

Вот части, которые у вас уже были, с некоторыми незначительными настройками:

public class Account
{
    //some account information and behavior
}

public interface ISecurityContext
{
}

public class UsernamePasswordContext : ISecurityContext
{
    public string Username { get; set; }
    public string Password { get; set; }
}

public class SessionContext : ISecurityContext
{
    public string SessionId { get; set; }
}

Вот ваш сервис аккаунта и его реализация:

public interface IAccountService
{
    Account GetAccountFromSecurityContext(ISecurityContext securityContext);
}

public class AccountService : IAccountService
{
    readonly IAccountFactory _accountFactory;

    public AccountService(IAccountFactory accountFactory)
    {
        _accountFactory = accountFactory;
    }

    public Account GetAccountFromSecurityContext(ISecurityContext securityContext)
    {
        Account account = _accountFactory.Create(securityContext);
        return account;
    }
}

Итак, вы можете видеть здесь, что я ввел IAccountFactory, который будет обрабатывать фактическое создание (поиск, что угодно) объекта Account.На данный момент все, что нас волнует, - это то, что учетная запись создается / извлекается ... нас не волнует, как это сделать.


Существует несколько способов реализации подобной фабрики.Один из способов - использовать тип стратегии, где у вас есть список виджетов, которые знают, как разрешить учетную запись.Затем вы просто выбираете соответствующий виджет (стратегию) и выполняете его.Нечто похожее на это может быть фабрика, которая использует IOC или локатор службы для разрешения типа, который был ранее зарегистрирован в конфигурации приложения.

В качестве примера, вот одна из возможных реализаций IAccountFactory с использованиемCommonServiceLocator:

public interface IAccountFactory
{
    Account Create(ISecurityContext securityContext);
}

public class ServiceLocatorAccountFactory : IAccountFactory
{
    readonly IServiceLocator _serviceLocator;

    public ServiceLocatorAccountFactory(IServiceLocator serviceLocator)
    {
        _serviceLocator = serviceLocator;
    }

    public Account Create(ISecurityContext securityContext)
    {
        var resolverType = typeof (IAccountResolver<>).MakeGenericType(securityContext.GetType());            
        dynamic resolver = _serviceLocator.GetInstance(resolverType);
        return resolver.Resolve(securityContext);
    }
}

Моя фабрика выходит из контекста локатора службы и получает любой распознаватель, соответствующий нашему контексту безопасности.Вот несколько примеров возможных распознавателей:

public interface IAccountResolver<in TSecurityContext> where TSecurityContext : ISecurityContext
{
    Account Resolve(TSecurityContext securityContext);
}

public class UsernamePasswordAccountResolver : IAccountResolver<UsernamePasswordContext>
{
    readonly IRepository _repository;

    public UsernamePasswordAccountResolver(IRepository repository)
    {
        _repository = repository;
    }

    public Account Resolve(UsernamePasswordContext securityContext)
    {
        var account = _repository.GetByUsernameAndPassword(securityContext.Username,
                                                           securityContext.Password);

        return account;
    }
}

public class SessionAccountResolver : IAccountResolver<SessionContext>
{
    public Account Resolve(SessionContext securityContext)
    {
        //get the account using the session information
        return someAccount;
    }
}

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

...