3

建模这个我想是这样如何DDD和存储库模式

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 
    } 


} 

在上面的代码我没有LIK编那么多,如果别人 所以我尝试引入多态性

所以在我ISecurityContext界面我添加了所有子类将实现

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

} 
一个GetAccount方法

但这里的问题是,我从我的UsernamePasswordContext POCO调用服务/存储库,这说明DDD

那么我可以通过其他方式来模拟这种情况。

+0

我认为当你添加帐户服务并用它来根据上下文生成帐户时你是在正确的线上,尽管我可能会使用工厂来生成基于上下文类型 – Dave 2012-02-16 16:30:11

+0

的帐户,但是,工厂将需要参考存储库,这将再次违反DDD – 2012-02-16 17:13:59

+1

你在这里做什么?你认为'UsernamePasswordContext'是你域中的一个实体吗?你提供的例子表明你试图将你的逻辑放在服务和存储库中。更多的DDD方法会把你的大部分逻辑放到你的领域模型中(你可能已经在做,但你的例子让我感到困惑)。 – 2012-03-27 11:37:45

回答

1

我认为你离解决方案不远。在这种情况下,我会将工厂注入您的AccountService,这将承担if..then..else的责任。然后,工厂可以使用许多可能的解决方案之一。

我会马上做出的一个改变是我会让你的AccountService实现一个接口,它应该使它更容易注入。假设你正在使用一些IOC容器,你不应该过分担心依赖关系,因为你让容器处理所有这些。

这里是你已经有碎片,有一些小的ajustments:

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或服务定位器来解析之前在应用程序配置中注册的类型的工厂。

在示例中的方式,这是一个使用CommonServiceLocator一个可能实现的IAccountFactory

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容器注册的解析器,使他们可以在服务定位器试图解决他们在工厂被发现。

+0

谢谢你的出色答案。你能否告诉我_serviceLocator.GetInstance(resolverType)的实现;那真是太好了...... – 2012-10-16 10:18:50

+0

GetInstance的实现在Microsoft的CommonServiceLocator库里面(http://commonservicelocator.codeplex.com/)。 CommonServiceLocator基本上是您计划使用的任何IOC容器的适配器。 – 2012-10-16 18:11:37

+0

好的......明白了......谢谢 – 2012-10-17 07:00:24