6

在我的项目中,业务逻辑都在应用程序服务中,域服务只是一些实体,谁能告诉我或给我一个例子来展示如何在域驱动设计中将业务逻辑添加到域服务中?很感谢!

更新

我写了一个简单的解决方案,这个解决方案是一个投票系统,解决方案的主要部分是:

在此处输入图像描述

Vote.Application.Service.VoteService.cs:

namespace Vote.Application.Service
{
    public class VoteService
    {
        private IVoteRepository _voteRepository;
        private IArticleRepository _articleRepository;

        public VoteService(IVoteRepository voteRepository,IArticleRepository articleRepository)
        {
            _voteRepository = voteRepository;
            _articleRepository = articleRepository;
        }

        public bool AddVote(int articleId, string ip)
        {
            var article = _articleRepository.Single(articleId);
            if (article == null)
            {
                throw new Exception("this article not exist!");
            }
            else
            {
                article.VoteCount++;
            }

            if (IsRepeat(ip, articleId))
                return false;

            if (IsOvertakeTodayVoteCountLimit(ip))
                return false;

            _voteRepository.Add(new VoteRecord()
            {
                ArticleID = articleId,
                IP = ip,
                VoteTime = DateTime.Now
            });

            try
            {
                _voteRepository.UnitOfWork.Commit();
                return true;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        private bool IsRepeat(string ip, int articleId)
        {
            //An IP per article up to cast 1 votes
            //todo
            return false;
        }

        private bool IsOvertakeTodayVoteCountLimit(string ip)
        {
            //An IP per day up to cast 10 votes
            //todo
            return false;
        }
    }
}

Vote.Domain.Contract.IVoteRepository.cs:

namespace Vote.Domain.Contract
{
    public interface IVoteRepository
        : IRepository<VoteRecord>
    {
        void Add(VoteRecord model);
    }
}

Vote.Domain.Contract.IArticleRepository.cs:

namespace Vote.Domain.Contract
{
    public interface IArticleRepository
        : IRepository<Article>
    {
        void Add(VoteRecord model);

        Article Single(int articleId);
    }
}

投票.域.实体.投票记录:

namespace Vote.Domain.Entities
{
    public class VoteRecord
    {
        public int ID { get; set; }

        public DateTime VoteTime { get; set; }

        public int ArticleID { get; set; }

        public string IP { get; set; }
    }
}

投票.域.实体.文章:

namespace Vote.Domain.Entities
{
    public class Article
    {
        public int ID { get; set; }

        public string Title { get; set; }

        public string Content { get; set; }

        public int VoteCount { get; set; }
    }
}

我想将application.service中的业务登录移动到Domain.service(当前不是这个项目),谁能帮助我?怎么做才合理?很感谢!

4

3 回答 3

7

DDD 专注于如何设计领域模型以适应需求,数据库中的模式并不重要。

如果您的域实体只是财产包,那么您似乎违反了贫血模型反模式。业务逻辑应该在域实体中。因此,在您的情况下,为了避免业务逻辑泄漏到应用程序服务。例如,如果需要,您可以使用一个名为 Client 的新模型来存储 Ip 或其他属性。

为了更容易理解,Client 是否超出了一天的限制,这个方法应该在 Client 类中。与方法 IsRepeated 类似。

因此,您的域对象应该是:

public class Client
{
    public string Ip { get; set; }
    // More properties if needed

    public List<Vote> Votes { get; set; }

    public bool ExceedLimitInDay()
    {
    }
}

public class Vote
{ 
    public int Id { get; set; } 
    public DateTime VoteTime { get; set; } 
    public Article Article { get; set; } 
    public Client { get; set; } 
}

public class Article   
{   
    public int Id { get; set; }   
    public string Title { get; set; }   
    public string Content { get; set; }   

    public List<Vote> Votes { get; set; }

    public bool IsRepeated(string ip)
    {
        return Votes.Select(v => v.Client.Ip == ip).Any();      
    }
} 

注意:如果您不需要创建新表 Client,只需将其映射到 Vote 表即可。至于 VoteCount 属性,则无需,因为您可以根据 Vote 列表进行计数

于 2012-08-16T10:32:31.920 回答
2

我认为投票和文章是一个聚合体。我对您的域了解不多,但我认为每次投票仅对给定文章重要。投票不会在文章之间共享,因此它们应该被视为聚合的成员,而不是整个域的实体。

在我看来,Article 将是 Aggregate 的根实体,而 Vote 将是内部的成员实体。应用这种“模式”,您可以将所有业务逻辑封装在其中。

您可以在文章中添加 AddVote(...) 或类似的一些业务逻辑。

然后你可能想知道.. “好吧.. 但是持久性呢??”。由于您将 Article-Vote 定义为聚合,因此您将它们放在一起。如果您对文章执行 CRUD 操作,同时您将在其聚合成员(投票)中执行这些操作。因此,您可能需要 ArticleAggregate 的存储库,它将处理文章的投票。

希望这对你有意义。根据您的域选择最佳选项。

于 2012-08-23T14:46:52.183 回答
0

看一眼应用程序服务,我会说它几乎不是应用程序服务,它已经有点像域服务了,因为它捕获了一些域逻辑(而不是获取视图模型输入并将其映射到实体上)。但是,您确实有更大的问题:

您的聚合已关闭。您希望围绕一个 IP 地址强制执行两个不变量,对一篇文章进行投票(一个 ip 每篇文章只能投票一次,一个 ip 每天最多可以投票 10 次)。这两个名词都不适合(文章、投票)来跟踪这一点。

ArticleVotes 可能非常适合跟踪和强制执行单个 ip 对文章的投票,而 IPVotesPerDate 可能会跟踪单个 IP 地址每天的投票数。如果总票数足够低,您也许可以将 ArticleVotes 移动到 Article 聚合中(并且您可以将性能保持在您想要的位置)。如果每天投票的 IP 总数很低,则 IPVotesPerDate 可能会变成 VotesPerDate。

底线是 ip 和投票量将决定聚合的性能。这可能会迫使您对它们进行改造以适应您寻求的性能数字。你最好的办法是找到这些数字,以了解前进的方向。

从那里应该很明显,可以将所需的行为带入我提到的聚合中。因此,对域服务的需求可能会消失。我说可能,因为用例仍然是对文章投票的 ip。因此,这可能需要跨聚合进行一些协调,因此引入域服务。

于 2012-08-22T22:29:17.563 回答