3

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

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

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

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

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, ...);
    }
}
4

2 回答 2

6

IoC 有两种风格:您正在使用的Service Locator和您正在询问的Dependency Injection 。

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

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

现在,关于你的问题。

我不明白这样更好吗?

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

假设您将其包装在工厂中,那么允许(逻辑上如果不是实际上)为消息实体拥有不同的存储库是没有意义的?

当您想到测试时,它确实如此。您应该可以轻松地用可测试的实现(存根)替换您的 CUT 所依赖的任何服务。

于 2012-08-28T11:46:08.257 回答
2

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

看起来你的模型也太胖了。你不能把它分成更小的部分并使用组合吗?

构造函数应该只将所需的信息作为参数。它只是用来表示的。其他一切都可以使用属性设置器或方法进行设置。我倾向于使用私有设置器和公共方法,但它要求您使用基于任务的 UI 而不是 crud(恕我直言,CRUD 不适合 DDD)

于 2012-08-28T11:52:02.197 回答