DDD理论学习系列(13)-- 模块

1. 引言

Module,即模块,是指提供特定功能的相对独立的单元。提到模块,你肯定就会想到模块化设计思想,也就是功能的分解和组合。对于简单问题,可以直接构建单一模块的程序。而对于复杂问题,则可以先创建若干个较小的模块,然后将它们组装、链接在一起,从而构成复杂的软件系统。

在DDD中,模块的用途也是如此,通过分解领域模型为不同的模块,以降低领域模型的复杂性,提高领域模型的可读性。

2. DDD中的模块

模块是一个笼统的概念,比较宽泛,为了正确发挥模块的威力,理解模块的概念就十分重要。下面我们从具体的问题着手,来尝试说明模块的概念。

如何对在线商城的顾客进行建模?

对于顾客来说,一般需要维护顾客的个人信息、收货地址、支付方式。这些信息是紧密相关的,不可独立存在。我们可以抽象出三个简单的聚合CustomerAddressBook和 Wallet。那这些类该如何存放呢?是为每一个聚合创建一个文件夹存放还是放在同一个文件夹?我想答案不言而喻。
这三个聚合就是一个模块,一个客户模块。通过定义一个Customer文件夹,来将相关联的领域对象组合起来。而这个文件夹体现在C#中就是命名空间的概念。

再来看一个问题,如何设计在线商城的支付功能?

支付是在线商城中十分重要的一个环节,设计的好坏直接影响项目的成败。一般来说,针对于支付环节,我们应该单独放到支付子域中去处理,以维护领域的不变性,支付环节对应支付上下文,在支付上下文下,一些领域概念才能更清晰。为了提升支付体验,我们势必要支持多种支付方式,比如支付宝支付、微信支付、其他银行卡支付。在对接某一种支付方式时,我们就应该为其定义单独的模块,保证支付方式的独立性。同样,我们可以选择通过命名空间来实现模块化,也可以类似NopCommerce创建单独的项目来插件化开发集成每一种支付方式。同样,我们也可以将整个支付功能拧出一个单独的支付模块,以便在其他项目中进行共用。

如何集成第三方SDK?

我们知道开源的一大好处是,大牛们分享了一系列高效、实用库或软件,也就是大家常说的“轮子”,比如Hangfire、RabbitMQ、Dapper、Redis等等,我们可以直接开箱即用。但如果项目中集成很多的第三方SDK,如果不加以组织整理,项目的结构就会比较混乱,代码的可读性就大大降低。这个时候我们就可以考虑模块化的去集成第三方SDK,通过对第三方SDK的再封装,来完善代码的组织结构,以达到项目中的统一调用。Abp框架就是通过这种方式来集成比较流行第三方SDK。

通过以上的举例说明,我们可以看到模块可大可小,每个模块都是相对独立的功能单元。在C#中我们可以用命名空间或单独的项目来实现模块。通过模块来组织和封装相关概念,来分解领域模型,以简化领域模型的复杂性。

但不要将模块与子域和限界上下文混淆。在复杂的领域模型中,为了对领域模型中进行准确建模,需要将领域模型拆分成多个子域,每个子域对应一个或多个限界上下文。在限界上下文中,可以将限界上下文中具体的领域概念分解成不同的模块。所以,从子域到限界上下文再到模块,应该是依次包含关系。

3. 模块设计的原则

模块的设计是基于领域模型的,要符合通用语言的表述。其次,模块的设计要符合高内聚低耦合的设计思想。

3.1. 根据领域来组织模块

模块应该由领域的概念来组织,而不是根据通用的组件类型和模式来创建模块。如果将所有的聚合、服务、工厂分别放在独立的模块中,就会有悖于DDD的设计原则,同时还会限制我们创建富有行为的领域模型。这样设计的模块的关注点是在当前的组件和模式上,而不是在领域上。每个模块都应该有适当的类来建模领域的特定方面的概念和功能。

3.2. 基于通用语言

项目中的通用语言除了用来指导实体,值对象、领域服务和领域事件的的命名外,也适用于模块的命名。使用通用语言来为模块命名,可以清晰的反映领域中的概念,且能够明确模块职责。例如,领域中身份认证的概念,我们就可以以Identity来命名这个模块。

推荐的模块命名规范是:公司名称.项目名称.架构分层.限界上下文.组件类型
比如对腾讯微信产品的朋友圈模块的领域层可以按以下方式命名:

Tencent.Weixin.Domain.Moment.Models Tencent.Weixin.Domain.Moment.RepositoriesTencent.Weixin.Domain.Moment.ServicesTencent.Weixin.Domain.Moment.Factories

说到这里,你可能会想到mvc的项目结构也是基于模块的思想,比如Models、Views、Controllers、css、js都是放在独立的文件夹中,这其实也是关注点分离的思想,通过模块的分割来达到关注点分离。

3.3. 高内聚低耦合

高内聚低耦合是模块设计的重要思想,模块内高内聚,模块间低耦合。
一个完整的系统,模块与模块之间,尽可能的使其独立存在。也就是说,让每个模块,尽可能的独立完成某个特定的子功能。模块与模块之间的接口,尽量的少而简单。如果某两个模块间的关系比较复杂的话,最好首先考虑进一步的模块划分,这样有利于修改和组合。

4. 总结

模块是对领域模型进行分解后的产物,是相对独立的功能单元,由一系列高内聚的领域对象组成,相对聚合、实体和值对象来说是更高一层的抽象。

模块化的思想大大简化了领域模型的复杂性,即便于我们设计出高内聚低耦合的系统,也便于我们理解系统的设计。

而至于模块的实现,我们既可以通过命名空间来进行分离,也可以使用单独的项目来实现。

参考资料

What are Modules in Domain Driven Design?

相关文章

  • DDD理论学习系列(1)-- 通用语言

  • DDD领域驱动之干货 (一)

  • DDD理论学习系列(2)-- 领域

  • DDD理论学习系列(3)-- 限界上下文

  • DDD理论学习系列(4)-- 领域模型

  • 事件总线知多少(2)

  • DDD理论学习系列(5)-- 统一建模语言

  • DDD理论学习系列(6)-- 实体

  • DDD理论学习系列(7)-- 值对象

  • DDD理论学习系列(8)-- 应用服务&领域服务

  • DDD理论学习系列(9)-- 领域事件

  • DDD理论学习系列(10)-- 聚合

  • DDD理论学习系列(11)-- 工厂

  • DDD理论学习系列(12)-- 仓储

  • 从事件和DDD入手来构建微服务

  • DDD领域驱动之干货 (一)

  • WeText项目:一个基于.NET实现的DDD、CQRS与微服务架构的演示案例

  • 【DDD/CQRS/微服务架构案例】在Ubuntu 14.04.4 LTS中运行WeText项目的服务端

  • 基于.NET CORE微服务框架 -surging的介绍和简单示例 (开源)

  • 剥析surging的架构思想

  • 基于.NET CORE微服务框架 -谈谈surging的服务容错降级

  • 我眼中的ASP.NET Core之微服务

  • .NET Core 事件总线,分布式事务解决方案:CAP

原文地址:http://www.cnblogs.com/sheng-jie/p/7266557.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/324297.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

POJ2352-Stars【树状数组】

正题 题目链接: http://poj.org/problem?id2352 题意 有n个坐标不同的星星,一个星星的等级等于在它左下的所有星星数量,求各个等级的星星数。 注:输入顺序保证Y坐标是升序,Y坐标相同的情况下X坐标也是升序的。 解题思路 用树…

html的<input type='radio'/>change事件坑

一、坑复现 <div><input typeradio nametest value1 checked/>1<span idtest_a>a test </span ></div> <div><input typeradio nametest value2/>2<span idtest_b>b test </span ></div> $(name"test"…

快速搭建Springboot项目的两种方式!!

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号【雄雄的小课堂】。前言Springboot的特点就是简单、快速和方便&#xff0c;使用idea不到一分钟就可以快速搭建springboot项目&#xff0c;并且&#xff0c;在这里&#xff0c;你不用写spring的那些乱七八糟的xml文件&…

简化springboot部署,太灵活方便了!

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号【雄雄的小课堂】。前言Springboot项目的编写与开发想必大家都会了&#xff0c;是不是和我们之前的项目比起来&#xff0c;简单方便了许多&#xff1f;今天&#xff0c;我们来看看除了可以直接在idea中部署和运行项目…

POJ2481-Cows【树状数组】

正题 题目链接: http://poj.org/problem?id2481 题目大意 给出若干个区间[Si,Ei]&#xff0c;定义一个区间比另一个区间“strong”当且仅当Si<Sj and Ei>Ej and Ei-Si>Ej-Sj。输出对于每一个区间&#xff0c;有多少个区间比它strong。区间最多100000个&#xff0c…

html数据复制到剪切板

一、原生js指令复制 function copyUtil(info) {var $textArea $(<textarea></textarea>);$textArea.val(info);$textArea.css(opacity,0);$(body).append($textArea);$textArea.select();//通过执行copy指令将选中的信息复制到剪切板var status document.execCo…

月旦评 之 DevOps招贤令

公元164-182年间&#xff0c;汝南平舆的许氏兄弟于每月初一品评人物&#xff0c;褒贬时政&#xff0c;被称为“月旦评”。所谓“子治世之能臣&#xff0c;乱世之奸雄也”这句许邵评价曹操的话也是来自于“月旦评”&#xff1b;《军事联盟》中杨修与司马懿的唇枪舌剑的精彩场景相…

springboot中配置mybatis别名该怎么写?

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号【雄雄的小课堂】。今天给大家分享的是&#xff0c;在springboot配置文件中&#xff0c;如何给mybatis实体类起别名。在以前&#xff0c;我们写mybatis的时候&#xff0c;有一个文件为mybatis-config.xml&#xff0c;…

P3321-Apple Tree【树状数组】

正题 题意 有一颗树&#xff0c;开始每个点的值都是1&#xff0c;有两种操作&#xff1a; 1.将一个点的值取反 2.询问一个子树的值的和 解题思路 用后续遍历就可以做到用一个区间代表一棵子树。然后用线段树就好了。 代码 #include<cstdio> using namespace std; st…

Redola.Rpc 集成 Consul 服务发现

Redola.Rpc 解决了什么问题&#xff1f; Redola.Rpc 是一个使用 C# 开发的 RPC 框架&#xff0c;代码开源在 GitHub 上。目前版本仅支持 .NET Framework 4.6 以上版本&#xff0c;未来待系统稳健后再考虑移植 .NET Standard 和 .NET Core。 Redola.Rpc 在 0.3.2 版本中&#…

springboot+springm vc+mybatis实现增删改查案例!

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号【雄雄的小课堂】。前言最近这几天都在看关于springboot的内容&#xff0c;每天新会获得点新收获&#xff0c;并且都总结发在公众号中&#xff1b;最后经过不懈努力&#xff0c;不断查找相关网页&#xff0c;解决各种…

【2018.5.12】模拟赛之一-ssl2413 排名【玄学】

正题 题目大意 就是给出4科排名&#xff0c;然后求两科的排名&#xff0c;按其中一科排名输出。 解题思路 水题不解释 代码 #include<cstdio> #include<algorithm> using namespace std; struct node{int c,m,e,x,ms; }a[46]; int n; bool cmp(node x,node y) {…

<table/>默认适应内容宽度造成滚动条不显示的解决方法

一、现象重现 <html><head></head><body> <table style"width: 100%;"> <tbody> <tr> <td style"width: 50%;overflow-x:auto"> <pre> 瞎子打灯笼一个盲人到亲戚家做客&#xff0c;天黑后&#xf…

【2018.5.12】模拟赛之二-ssl2414 简写单词【字符串】

正题 题目大意 若干个字符串&#xff0c;每个字符串求一个前缀&#xff0c;使只有这个字符串有这个前缀。 解题思路 O(n2)O(n2)枚举两个字符串&#xff0c;然后O(n)O(n)求出至少要取到哪里做前缀这两个字符串才不会冲突。 代码 #include<cstdio> #include<iostream&…

java中,如何实现输入一个正整数,并将这个数字反转输出,比如输入123,输出321

如题所示&#xff0c;在java中如何实现输入一个正整数&#xff0c;然后将这个正整数反着输出来&#xff0c;代码如下&#xff1a; public static void test7(){System.out.println("请输入一个正整数&#xff1a;");Scanner sc new Scanner(System.in);int num sc…

asp.net core 1.1 项目升级至 asp.net core 2.0 preview 2

这两天把一个 asp.net core 1.1 的项目迁移到了 asp.net core 2.0 preview 2 &#xff0c;在这篇随笔中记录一下。 如果项目在有 global.json 文件&#xff0c;需要删除或修改为 .net 2.0 preview 2 的 sdk 版本号。 对于类库项目的 .csproj&#xff0c;需要把 TagetFramewo…