3

我对DDD中的工厂存储库服务有一些疑问。我有以下实体:文件夹、文件、FileData。

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

所以我的第一个问题是我应该使用工厂来创建这个聚合还是由存储库决定?此时我有 2 个存储库,一个用于文件夹,另一个用于文件,但在我看来,我应该将它们合并在一起。以下代码片段显示了我的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
}

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

谢谢

4

1 回答 1

8

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

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

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

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

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

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

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

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

那么服务中的依赖注入呢,我应该从 UI 层使用 Unity 等 IOC 容器注入我的服务,还是应该只对服务中的依赖项进行硬编码?

这是一个偏好问题。如果您可以从使用 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();
}

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

于 2013-03-05T16:37:35.980 回答