简体   繁体   English

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

[英]How to model this in DDD and repository pattern

I want to model service like this 我想模仿这样的服务

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
    }



}

In the above methods i want to pass different type of SecurityContext So what i have did is 在上面的方法中,我想传递不同类型的SecurityContext,所以我所做的就是

Public Interface ISecurityContext
{

}

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

}

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

So In my Account Service i have a method 所以在我的账户服务中我有一个方法

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
    }


}

In the above code i didnt liked so many if else So i tried introducing polymorphism 在上面的代码我不喜欢这么多,如果否则所以我尝试引入多态

So in my ISecurityContext interface i added a GetAccount method which all sub class will implement 所以在我的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);
   }


}

and my account service will become like this 我的帐户服务将变成这样

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

}

But the problem here is that i am calling a service/repository from my UsernamePasswordContext POCO which voilates DDD 但这里的问题是我从我的UsernamePasswordContext POCO调用服务/存储库,它使DDD消失

So what are other ways i can model this scenario. 那么我可以用其他方式来模拟这种情况。

I think you're not far off from the solution. 我认为你离解决方案不远了。 In this case, I would inject a factory into your AccountService that would take on the responsibility of the if..then..else . 在这种情况下,我会在您的AccountService中注入一个工厂,该工厂负责if..then..else Then, the factory could use one of many possible solutions. 然后,工厂可以使用许多可能的解决方案之一。

One change I would make right off is I would make your AccountService implement an interface which should make it easier to inject later. 我将立即做出的一个改变是,我将使您的AccountService实现一个接口,以便以后更容易注入。 Assuming you're using some IOC container, you shouldn't have to worry too much about dependencies because you're letting the container handle all that. 假设你正在使用一些IOC容器,你不必过分担心依赖关系,因为你让容器处理所有这些。

Here are the pieces you already had, with some minor 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; }
}

Here's your account service along with it's implementation: 这是您的帐户服务及其实施:

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

So, you can see here that I've injected an IAccountFactory that will handle the actual creation (retrieval, whatever) of the Account object. 所以,你可以在这里看到我注入了一个IAccountFactory ,它将处理Account对象的实际创建(检索,无论如何)。 All we care about at this point is that the account gets created/retrieved... we don't care about how. 我们现在关心的是帐户被创建/检索...我们不关心如何。


There are a few ways you can implement a factory like this. 有几种方法可以实现这样的工厂。 One way is to use a type of strategy pattern where you have a list of widgets that know how to resolve an account. 一种方法是使用一种策略模式,其中有一个知道如何解析帐户的小部件列表。 Then you just pick the widget (strategy) that matches and execute it. 然后你只需选择匹配并执行它的小部件(策略)。 Something similar to this would be a factory that uses an IOC or service locator to resolve a type that has been registered previously in application configuration. 与此类似的是使用IOC或服务定位器来解析先前在应用程序配置中注册的类型的工厂。

In the way of an example, here's one possible implementation of IAccountFactory using CommonServiceLocator : 在一个实例的方式,这里有一个可能实现的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);
    }
}

My factory here goes out to the service locator context and grabs whatever resolver matches our security context. 我的工厂在这里转到服务定位器上下文并抓取任何解析器匹配我们的安全上下文。 Here are a couple examples of possible resolvers: 以下是可能的解析器的几个示例:

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

The only thing left is to register the resolvers in your IOC container so that they can be found when the service locator tries to resolve them in the factory. 剩下的唯一事情是在IOC容器中注册解析器,以便在服务定位器尝试在工厂中解析它们时找到它们。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM