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