如何在DDD和存储库模式中对此进行建模

时间:2012-02-16 13:50:25

标签: c# domain-driven-design repository polymorphism strategy-pattern

我想像这样建模服务

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 个答案:

答案 0 :(得分:1)

我认为你离解决方案不远了。在这种情况下,我会在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的{​​{1}}的一种可能实现方式:

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

唯一剩下的就是在IOC容器中注册解析器,以便在服务定位器尝试在工厂解决它们时找到它们。