功能说明
文章投票功能简单描述:用户阅读文章后,可以给文章投票,投票包括两个方向:支持或不支持。
设计思考
基于领域驱动设计常见的做法,首先可以确定的是文章Article
是一个聚合根。Article包含title,content,description等等。
有疑惑的地方是:投票Vote是否要单独出来做聚合根,还是把它放在Article聚合根下?需要考虑一下几点:
- Article和Vote是一对多的关系,但vote的数量是不确定的,如果把Vote放到Article的集合里,会存在加载Article性能问题以及内存额外消耗。
- Vote是否有自己特定的业务以及生命周期呢?如取消,支持和不支持等等
- Vote除了通过Article聚合查找外,是否需要按用户查找用户自己投票信息列表呢?
- 如果把Vote放到Article里,那么收藏,评论等类似功能是否也要放到Article里,最后Article就会演变称一个大聚合,虽然说保证了聚合内规则的一致性,但是一个类承担了多个责任。
文章Effective Aggregate Design Part I: Modeling a Single Aggregate针对大聚合的问题做了比较详细的分析,其中一个原则是:尽量设计小的聚合。
基于以上考虑,把Vote作为单独的聚合根来设计。
单独Vote聚合根设计
简单投票功能
简单描述投票的领域语义:用户对文章投了票。代码表示为:
article.votedBy(readId)
这里的votedBy是一个工厂方法,它是Article用来创建投票的方法,实现如下:
//在Article类里
public Vote votedBy(UserId readerId) {
return new Vote(this.id, readerId);
}
在应用服务层的ArticleApplicationService,可以这样调用:
public void voteArticle(UserId readId, ArticleId articleId) {
Article article = articleRepository.get(articleId);
Vote vote = article.votedBy(readId);
voteRepository.save(vote);
}
支持和不支持投票代码重构
对于投票要分为支持和不支持两种情况,那么以上代码就要重构下。
//Article类的方法
//用户投支持票
public Vote likedBy(UserId readerId) {
return Vote.positiveByOn(readerId, this.id);
}
//用户投不支持票
public Vote unlikedBy(UserId readerId) {
return Vote.negativeByOn(readerId, this.id);
}
对于Vote类实现代码简单如下:
public class Vote {
privte UserId readerId;
private Article articleId;
private VoteTpe type;
private Vote(UserId readerId,ArticleId articleId,VoteType voteType) {
this.readerId = readerId
this.articleId = articleId
this.type = voteType
}
public Vote static positiveByOn(UserId readerId,ArticleId articleId) {
return new Vote(readerId, articleId, VoteType.POSITIVE);
}
Vote static negativeByOn(UserId readerId,ArticleId articleId) {
return new Vote(readerId, articleId, VoteType.NEGATIVE);
}
}
public Enum VoteType { POSITIVE, NEGATIVE }
Vote类也是提供了两个静态的工具方法,用于创建支持和不支持两种情况的投票。