DDD 领域驱动设计-看我如何应对业务需求变化,领域模型调整?
“愚蠢的应对”,这个标题是我后来补充上的,博文中除了描述需求变化、愚蠢应对和一些思考,确实没有实质性的应对,文不对题,实在惭愧。 这次应对,我们从领域模型开始。 领域模型思考业务需求变化,关于领域模型的调整,上一篇我只给出了一些思考,但这段内容,我觉得是那篇博文最重要的地方,不知道你仔细看了没,我一直在强调“回复的概念”,以及之前领域模型没有“回复”所造成的一些问题,在上一个版本的领域模型中,对消息的操作,除去本身状态的改变,就只有发送消息操作,也就是 ISendMessageService 领域服务接口,在短消息应用场景中,是有回复和转发操作的,但之前的设计把回复和转发的消息也看作是“消息”,一个完整的“消息”,它和第一次发送的消息是一样的,说是完整,其实也是独立的,我们可以对它进行独立操作,但这也就造成了回复概念的模糊,比如应用层中的 SendMessage/ReplyMessage/ForwardMessage 操作,大部分都是重复代码,最后调用同一个 ISendMessageService 领域服务实现,从应用层的这部分代码,就可以看出,现在领域模型所暴露出来的一些问题。当然不止这些,后来在“愚蠢的应对”中,最后所出现的性能问题,追根究底也是这个原因,因为现在消息的“独立性”,致使消息之间没有任何关联,所以我们在消息仓储进行取出消息对象操作,这个就像是进行所有消息对象的过滤,我所规定的过滤条件是标题和收发件人,然后再进行发送时间降序排序,取出最新发送的那一条消息,当然条件和转换还有很多,最后使用 ORM 生成了一大串的 SQL 代码,然后就优化,再优化,最后就陷入泥潭了。。。 所有的一些问题出现,追根究底都是领域模型设计不合理所导致的,从这一方面就可以体现出领域模型的重要性。 回复是现在领域模型调整的核心,在上一篇博文评论中,针对现有领域模型的调整,我和 ntefocus 探讨了两种方式,还有后来徐少侠、翱翔提出的第三种方式,这边我再大致总结一下,详细内容可以看上一篇的评论。 领域模型调整的三种方式:
针对上面每一种所出现的细节问题,我们探讨了很久,可能我描述的不是很准确,这边只需要明白每一种所表达的意思,针对其实现,没谁对谁错,只有适不适合,每一种改变,都会对应一个新的领域模型产生。 最后,我所采用的是第二种方式,原因在评论中也有详细的说明,这边我再简单叙述下:
当然这种方式最大的缺点就是回复属性的冗余,有利有弊,没有什么完美的,我们来看一下领域模型模型的具体调整。 领域模型调整我直接贴一下领域模型的调整代码,首先是 Message 实体中,增加 ParentMessage 属性,用来表示回复的概念: public Message ParentMessage { get; set; }
这边需要注意的是,ParentMessage 属性类型为 Message,而不是之前描述的 parentId,Id 标识的概念具体会体现在 ORM 映射中,领域模型中应该是 Message 对象。 using CNBlogs.Msg.Domain.Entity;
using CNBlogs.Msg.Domain.ValueObject;
using CNBlogs.Msg.Infrastructure;
namespace CNBlogs.Msg.Domain.DomainService
{
/// <summary>
/// ReplySiteMessageService 领域服务-回复消息
/// </summary>
public class ReplySiteMessageService
{
bool ReplySiteMessage(Message parentMessage,Message replyMessage)
{
if (parentMessage.Sender == replyMessage.Sender && parentMessage.Recipient == replyMessage.Recipient)
{
if (parentMessage.DisplayType == MessageDisplayType.Outbox)
{
parentMessage.DisplayType = MessageDisplayType.OutboxAndInbox;
}
else
{
throw new CustomMessageException("消息已被您删除,无法回复");
}
}
else if (parentMessage.Sender == replyMessage.Recipient && parentMessage.Recipient == replyMessage.Sender)
{
if (parentMessage.DisplayType == MessageDisplayType.Inbox)
{
parentMessage.DisplayType = MessageDisplayType.OutboxAndInbox;
}
else
{
"您不是收发件人,没有权限回复");
}
replyMessage.ParentMessage = parentMessage;
return true;
}
}
}
上面 ReplySiteMessageService 领域服务中,我只写了一个权限判断的代码,可能以后会有所拓展,如果你熟悉之前 SendSiteMessageService 领域服务的代码,就会发现它们是有所不同的,这也就是发送和回复要进行隔离开,但它们本质都是消息,也就是同一个实体概念。 为了方便大家查看短消息领域模型的代码,我把它上传到 GitHub 了,感兴趣的话,可以参考下。
写在最后
在领域驱动设计的过程中,上面那句话常常挂在嘴边,但当实际操作的时候,却往往会把它忽略,这次领域模型调整的代码虽然很少,但是却思考了很久,核心内容确定下来,后面的一些操作才能够围绕它展开。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |