【问题标题】:Factories, services, repository in DDDDDD 中的工厂、服务、存储库
【发布时间】:2013-02-19 13:06:21
【问题描述】:

我对 DDD 中的factoriesrepositoriesservices 有一些疑问。我有以下实体:文件夹、文件、FileData。

在我看来,“文件夹”是一个聚合根,应该负责创建 File 和 FileData 对象。

所以我的第一个问题是我应该使用 factory 来创建这个聚合还是由 repository 决定?此时我有 2 个存储库,一个用于文件夹,另一个用于文件,但在我看来,我应该将它们合并在一起。以下代码 sn-p 显示了我的 Folder Repository,它位于我的基础架构层中:

public class FolderRepository : IFolderRepository
{
    #region Fields

    private readonly IFolderContext _context;
    private readonly IUnitOfWork _unitOfWork;

    #endregion

    #region Constructor

    public FolderRepository(IUnitOfWork unitOfWork)
    {
        _unitOfWork = unitOfWork;
        _context = _unitOfWork.Context as IFolderContext;
    }

    #endregion

    public IUnitOfWork UnitOfWork
    {
        get { return _unitOfWork; }
    }

    public IQueryable<Folder> All
    {
        get { return _context.Folders; }
    }

    public Folder Find(Guid id)
    {
        return _context.Folders.Find(id);
    }

    public void InsertGraph(Folder entity)
    {
        _context.Folders.Add(entity);
    }

    public void InsertOrUpdate(Folder entity)
    {
        if (entity.Id == Guid.Empty)
        {
            _context.SetAdd(entity);
        }
        else
        {
            _context.SetModified(entity);
        }
    }

    public bool Delete(Guid id)
    {
        var folder = this.Find(id) ?? _context.Folders.Find(id);
        _context.Folders.Remove(folder);

        return folder == null;
    }

    public int AmountOfFilesIncluded(Folder folder)
    {
        throw new NotImplementedException();
        //return folder.Files.Count();
    }

    public void Dispose()
    {
        _context.Dispose();
    }
}

接下来我在我的应用层中创建了一个服务,称为“IoService”。我对服务的位置有疑问。是否应该移到领域层

public class IoService : IIoService
{
    #region Fields

    private readonly IFolderRepository _folderRepository;
    private readonly IFileRepository _fileRepository;
    private readonly IUserReferenceRepository _userReferenceRepository;

    #endregion

    #region Constructor

    public IoService(IFolderRepository folderRepository, IFileRepository fileRepository, IUserReferenceRepository userReferenceRepository)
    {
        if(folderRepository == null)
            throw new NullReferenceException("folderRepository");
        if(fileRepository == null)
            throw new NullReferenceException("fileRepository");
        if (userReferenceRepository == null)
            throw new NullReferenceException("userReferenceRepository");

        _folderRepository = folderRepository;
        _fileRepository = fileRepository;
        _userReferenceRepository = userReferenceRepository;
    }

    #endregion

    #region Folder Methods

    /// <summary>
    /// Create a new 'Folder'
    /// </summary>
    /// <param name="userReference"></param>
    /// <param name="name"></param>
    /// <param name="parentFolder"></param>
    /// <param name="userIds">The given users represent who have access to the folder</param>
    /// <param name="keywords"></param>
    /// <param name="share"></param>
    public void AddFolder(UserReference userReference, string name, Folder parentFolder = null, IList<Guid> userIds = null, IEnumerable<string> keywords = null, bool share = false)
    {
        var userReferenceList = new List<UserReference> { userReference };

        if (userIds != null && userIds.Any())
        {
            userReferenceList.AddRange(userIds.Select(id => _userReferenceRepository.Find(id)));
        }

        var folder = new Folder
        {
            Name = name,
            ParentFolder = parentFolder,
            Shared = share,
            Deleted = false,
            CreatedBy = userReference,
            UserReferences = userReferenceList
        };

        if (keywords != null)
        {
            folder.Keywords = keywords.Select(keyword =>
                new Keyword
                {
                    Folder = folder,
                    Type = "web",
                    Value = keyword,
                }).ToList();
        }

        //insert into repository
        _folderRepository.InsertOrUpdate(folder);

        //save
        _folderRepository.UnitOfWork.Save();
    }

    /// <summary>
    /// Get 'Folder' by it's id
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public Folder GetFolder(Guid id)
    {
        return _folderRepository.Find(id);
    }

    #endregion

    #region File Methods

    /// <summary>
    /// Add a new 'File'
    /// </summary>
    /// <param name="userReference"></param>
    /// <param name="folder"></param>
    /// <param name="data"></param>
    /// <param name="name"></param>
    /// <param name="title"></param>
    /// <param name="keywords"></param>
    /// <param name="shared"></param>
    public void AddFile(UserReference userReference, Folder folder, FileData data, string name, string title = "", IEnumerable<string> keywords = null, bool shared = false)
    {
        var file = new File
        {
            Name = name,
            Folder = folder,
            FileData = data,
            CreatedBy = userReference,
            Type = data.Type
        };

        if (keywords != null)
        {
            file.Keywords = keywords.Select(keyword =>
                new Keyword
                {
                    File = file,
                    Type = "web",
                    Value = keyword,
                }).ToList();
        }

        folder.Files.Add(file);
        folder.Updated = DateTime.UtcNow;

        _folderRepository.InsertOrUpdate(folder);

        //save
        _folderRepository.UnitOfWork.Save();
    }

    /// <summary>
    /// Get 'File' by it's id
    /// </summary>
    /// <param name="id"></param>
    /// <returns></returns>
    public File GetFile(Guid id)
    {
        return _fileRepository.Find(id);
    }

    #endregion
}

总结一下: 我是否应该使用该服务来创建文件夹对象。或者服务应该只使用一个工厂,它负责创建对象并将创建的对象发送到存储库?服务中的依赖注入怎么样,我应该使用 Unity 等 IOC 容器从 UI 层注入我的服务,还是应该只对服务中的依赖项进行硬编码?

谢谢

【问题讨论】:

    标签: domain-driven-design factory-pattern ddd-repositories ddd-service


    【解决方案1】:

    所以我的第一个问题是我应该使用工厂来创建这个聚合 还是取决于存储库?

    工厂负责创建,而存储库负责持久性。重构后,存储库将有效地创建实例。然而,这个创建过程通常是通过反射完成的,并且不会通过工厂来阻止应该只在创建时发生的初始化。

    此时我有 2 个存储库,一个用于文件夹,另一个用于 文件,但在我看来我应该将它们合并在一起。

    在 DDD 中,每个聚合都有一个存储库。该存储库将负责持久化作为聚合一部分的所有实体和值对象。

    我对服务的位置有疑问。是否应该移动 到领域层?

    IMO,一个应用服务可以被放置到领域层,因为它已经作为一个门面,并且将它们保持在一起将带来凝聚力的好处。关于IoService 的一种想法是,诸如AddFile 之类的方法通常会通过聚合标识而不是实例来参数化。由于应用程序服务已经引用了一个存储库,它可以根据需要加载适当的聚合。否则,调用代码将负责调用存储库。

    我应该使用该服务来创建文件夹对象吗?或者应该 服务只是使用一个工厂,它有责任创造 对象并将创建的对象发送到存储库?

    IoService 看起来不错,除了前面的评论是通过身份而不是实例进行参数化。

    服务中的依赖注入怎么样,我应该注入我的 使用 Unity 等 IOC 容器提供来自 UI 层的服务,或者我应该 只是硬编码服务中的依赖项?

    这是一个偏好问题。如果您可以从使用 IoC 容器中受益,请使用它。但是,不要仅仅为了使用它而使用它。您已经在进行依赖注入,只是没有花哨的 IoC 容器。

    示例

    class File
    {
        public File(string name, Folder folder, FileData data,  UserReference createdBy, IEnumerable<string> keywords = null)
        {
            //...
        }
    }
    
    ...
    
    class Folder
    {
        public File AddFile(string name, FileData data, UserReference createdBy, IEnumerable<string> keywords = null)
        {
            var file = new File(name, this, data, createdBy, keywords)
            this.Files.Add(file);
            this.Updated = DateTime.UtcNow;
            return file;
        }
    }
    
    ...
    
    public void AddFile(UserReference userReference, Guid folderId, FileData data, string name, string title = "", IEnumerable<string> keywords = null, bool shared = false)
    {
        var folder = _folderRepository.Find(folderId);
        if (folder == null)
            throw new Exception();
    
        folder.AddFile(name, data, keywords);
    
        _folderRepository.InsertOrUpdate(folder);
        _folderRepository.UnitOfWork.Save();
    }
    

    在此示例中,更多的行为被委托给文件夹聚合和文件实体。应用程序服务简单地调用聚合上的适当方法。

    【讨论】:

    • 非常感谢您的回复。你能给我一个关于如何编写 AddFile 方法的简短示例,以便我对这个主题 100% 清楚。
    • 非常好,非常感谢,现在我更清楚了。
    • 那么假设你想通过它的 id 拥有一个文件,你需要在文件夹存储库中添加一个方法来接收文件?
    • 依赖注入以及 IoC 的可能用法在您的示例中实际上没有表示。查看 addFile 函数。此函数创建一个 File 对象。例如,在(单元)测试中,您不能将其交换为具有相同属性的模拟类。您仍然紧密耦合某些类。有了这个,请看单一责任原则。您正在让您的文件夹创建文件,而不是它应该做的事情(管理其自身的文件集合)
    • @mvbrakel 我也听说过,这让我很困惑。所以文件对象应该在IoService的AddFile方法中实例化,并在调用folder.AddFile()之前让_fileRepository来存储,对吧?
    猜你喜欢
    • 1970-01-01
    • 2019-04-23
    • 2018-09-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-30
    相关资源
    最近更新 更多