好的设计DDD和IoC,如何将IRepository注入模型

时间:2012-08-28 11:34:00

标签: c# domain-driven-design inversion-of-control

我有一个复杂的实体(Message),它有一个非常重要的构造函数(13个参数),其中一些参数依次是实体(Verb)。

我需要一些其他实体的存储库(例如某些默认值)。

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

简化代码(我将默认动词列表作为静态构造函数个人构建的静态对象,如果我的消息实体需要某种IRepositry的话,这是最简单的naff示例。)

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之外高出很多(假设我的网络服务接受了消息的创作)

public class MessageWebService
{
    private static IVerbRepository _verbRepository;

    public void AddMessage(some parameters)
    {
        var message = new Message(_verbRepository, ...);
    }
}

2 个答案:

答案 0 :(得分:6)

您正在使用两种类型的IoC:服务定位器,以及您要询问的依赖注入

截至目前,Service Locator被认为是一种反模式,因为它引入了隐式依赖(通过查看类的公共接口无法弄清楚的依赖关系)并使测试更加困难。

另一方面,

依赖注入没有这些问题,但在类声明中往往更加冗长。

现在,关于你的问题。

  

我不明白这是怎么回事?

这是明确的。您可以看到您的课程取决于此服务或该服务。 BTW,你的类没有,它只使用动词库来定位默认动词(可以很容易地移出课堂外)。

  

假设你将它包装在一个工厂中,允许(逻辑上,如果不是真的)有不同的存储库用于消息引入是没有意义的吗?

当你想到测试时它会这样做。您应该可以轻松地使用可测试的实现(存根)替换您的CUT所依赖的任何服务。

答案 1 :(得分:2)

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

看起来你的模型太胖了。难道你不能把它分成小块并改用构图吗?

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