设计好DDD和IoC,如何在模型中注入IRepository



我有一个复杂的实体(Message),它有一个相当庞大的构造函数(13个参数),其中一些参数反过来又是实体(Verb)。

有很多事情我需要另一个实体的存储库(例如,对于一些默认值)。

使用IoC并保持代码干净/最佳实践的好方法是什么?

简化的代码(我将默认动词列表作为静态构造函数个人构建的静态对象,这是为什么我的Message实体需要某种IReposity的最简单的例子)。

private static IVerbRepository verbRepository;
static Message()
{
    using (IKernel kernel = new StandardKernel())
    {
        verbRepository = kernel.Get<IVerbRepository>();
    }
}
public Message(int id, string precis,
    DateTime created, DateTime validTo,
    PriorityType priority, Source source, SID createdBy,
    string content = null, string helpText = null,
    DateTime? validFrom = null, bool emailOnExpiry = false,
    IEnumerable<SID> targetUsers = null,
    IOrderedEnumerable<MessageVerb> verbs = null) : base(id)
{
    Verbs = verbs ??
            new List<MessageVerb>
            {
                new MessageVerb(
                verbRepository.GetByName("Acknowledge"), true,
                string.Empty)
            }.OrderBy(x => x.IsDefault);
    Precis = precis;
    Created = created;
    ValidTo = validTo;
    Priority = priority;
    Source = source;
    CreatedBy = createdBy;
    Content = content;
    HelpText = helpText;
    ValidFrom = validFrom;
    EmailOnExpiry = emailOnExpiry;
    TargetUsers = targetUsers;
}

常见的做法似乎是向构造函数添加一个额外的参数。我不明白这怎么会更好?这意味着每次您想要创建消息时,都需要编写代码来检索存储库。假设你在工厂中完成了这一点,那么允许(如果不是实际的话,逻辑上)为消息实体拥有不同的存储库是没有意义的?

编辑1

基于第一个解决方案,代码会这样,

public Message(IVerbRepository verbRepository ...) {  }

在同一域的其他地方组装

public MessageService
{
    private IVerbRepository VerbRepository {get; set;}
    public static IOrderedEnumerable<MessageVerb> DefaultVerb {get;}
}

在我的DDD(比如说我的接受消息创建的web服务)之外,要高得多

public class MessageWebService
{
    private static IVerbRepository _verbRepository;
    public void AddMessage(some parameters)
    {
        var message = new Message(_verbRepository, ...);
    }
}

IoC有两种风格:您正在使用的服务定位器和您正在询问的Dependency Injection

到目前为止,ServiceLocator被认为是一种反模式,因为它引入了隐式依赖关系(通过查看类的公共接口无法确定依赖关系),并使测试更加困难。

另一方面,依赖注入没有这些问题,但在类声明中往往更为冗长。

现在,关于你的问题。

我不明白这怎么会更好?

它是明确的。你可以看到你的类依赖于这个或那个服务。顺便说一句,你的类没有,它只使用动词存储库来定位默认动词(可以很容易地移动到类外)。

假设你在工厂中完成了这一点,那么允许(如果不是实际的话,逻辑上)为消息实体拥有不同的存储库是没有意义的?

当你想到测试时,它确实会发生。您应该能够很容易地用可测试的实现(存根)替换CUT所依赖的任何服务。

域模型不应该知道数据源=不要在其中使用存储库。您可能需要一个能够实现所需业务规则的服务类(服务可以使用存储库)。

看起来你的模特也太胖了。你不能把它掰成小块,用作文代替吗?

构造函数应仅将所需信息作为参数。它只是用来表明这一点。其他所有内容都可以使用属性setter或方法进行设置。我倾向于使用私有setter和公共方法,但这需要使用基于任务的UI而不是crud(imho crud也不太适合DDD)

最新更新