DDD中的工厂,服务,存储库

Joh*_*ohn 3 domain-driven-design ddd-repositories factory-pattern ddd-service

我有一些相关问题的工厂,仓库服务DDD.我有以下实体:文件夹,文件,FileData.

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

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

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

接下来,我在我的应用程序层创建了一个服务,这称为"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
}
Run Code Online (Sandbox Code Playgroud)

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

谢谢

eul*_*rfx 6

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

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

这时我有2个存储库,一个用于Folder,另一个用于File,但在我看来,我应该将它们合并在一起.

在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();
}
Run Code Online (Sandbox Code Playgroud)

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