文档库 最新最全的文档下载
当前位置:文档库 › 在ASP.NETMVC4中使用领域驱动设计

在ASP.NETMVC4中使用领域驱动设计

在ASP.NETMVC4中使用领域驱动设计
在ASP.NETMVC4中使用领域驱动设计

在领域驱动设计中,我们首先会为领域设计模型,且在设计的过程中完全不考虑存储和具体的实现细节。也就是说在设计中,我们把数据库放在了一个次要的位置(其实仍然很重要,只是在设计架构时我们不考虑它)。有了模型以后,下一步就是如何持久化(保存数据),且这里就存在着面向对象方式表示的数据和数据库所使用的基于元组的关系模型之间的不一致(对象-关系阻抗失谐)。如果可以选用面向对象数据库,事情就会容易许多,然而面向对象数据库并没有成为IT界的主流,因此关系型数据库就成为你唯一的选择。之所以会出现基于领域的设计是为了处理真实世界中的复杂性。运用领域驱动设计之后,你要么选用面向对像数据库,要么引入一个O/R映射层。

然而实现领域驱动设计很复杂,甚至可以说以个人之力完全无法实现。幸好现在有很多框架可用,例如Entity Framework(以下简称EF)。使用EF有三种方法:1.数据库优先,即先设计数据库,然后做数据库和面向对象模型的映射;2.模型优先,先用EF自带的设计工具设计模型,然后生成sql脚本,创建数据库;3.代码优先,先使用其他UML工具设计模型,根据模型手动编写模型代码,然后生成sql脚本,创建数据库。目前最流行的是代码优先,因为它最灵活,然而代码优先的工作量很大。而数据库优先的方法和领域驱动设计的思想相悖。所以我选择了模型优先的方法,但在EF4中,使用模型优先是有问题的,它生成的模型都继承自一个名为EntityObject的基类,这个基类包含了访问数据库的方法,这就不支持持久化透明了。幸好在EF4.1以后微软引入了DbContext,用EF4.1的模型优先可以生成支持持久化透明的实体类,不继承任何基类,数据访问由DbContext实现。在VS2012中创建一个https://www.wendangku.net/doc/d218273403.html, MVC4项目,VS2012会自动添加EF5.0的引用,并且在设计模型时会自动生成支持持久化透明的实体类,但在VS2010中要麻烦点,这里不做说明了,因为用了VS2012就完全没有问题了。具体建模过程不做介绍,网上一搜一大堆。下图为模型的一部分:

在传统的三层架构设计中,三层架构分为数据访问层、业务逻辑层和表现层。很多人在自己实现三层架构的时候都会明确的定义DAL、BLL和UI,但在实现的过程中总会有一些误解,例如很多人误把用户操作的流程当成业务逻辑,而数据访问层就是大量的sql语句和连接数据库的操作。实际上,用户的操作流程应该称为应用逻辑,应该放在服务层。我看过很多人设计的三层架构,BLL层几乎没有什么代码,只是简单的对DAL层的调用,复杂的数据访

问逻辑都在DAL层。可以说,这种三层架构并不是真正意义上的三层架构,只是看起来像三层架构。其实三层架构是一种很复杂的架构模式,个人之力很难实现。

在领域驱动设计中,业务逻辑层主要关注于领域的对像模型,每个业务对象都有其数据和行为,即业务逻辑层表示的是领域对象之间的关系逻辑,在你建模完成以后业务逻辑层就已经设计完成了,即使你一行代码都没写。例如上图的模型图,可以很直观的看出来各模型之间的关系,当我们需要时可以从一个模型很容易的导航到另一个模型,然后由EF的DbContext 访问数据库,而不需要编写任何sql语句。这样的设计并没有明确定义DAL、BLL,在项目中完全看不到这样的类或类库,这里的三层只是逻辑上的三层。DbContext负责数据访问,领域模型包含业务逻辑。但是在一般情况下,不应该在UI层直接使用DbContext访问数据库,而是要先定义一个仓储层(repository),这是领域驱动设计中最常用的做法,首先定义一个仓储接口,包含CRUD操作。如下图:

然后再定义一个Repository类实现这个接口:

这个类需要一个泛型参数,该参数的基类是DbContext,在构造方法里直接创建它。构造方

法还需要一个IErrorLogger类型的参数,用于记录访问数据库时出现的异常,通过依赖注入(Dependency Injection,DI)的方式传入(控制反转(IoC)原则,后面还将重点介绍。)

表现层使用的是https://www.wendangku.net/doc/d218273403.html, MVC4,这才是本文的重点。新建一个MVC4项目(过程不做介绍),然后新建一个名为ArticleController的控制器,在ArticleController控制器里新建一个名为Articles的控制器操作(action),用来处理用户对文章列表的请求:

这个控制器依赖于IRepository接口,通过IRepository访问数据库。这里似乎有个问题,是不是UI层直接调用数据访问层了呢?其实不是,这里的控制器仅依赖于IRepository接口,并非数据访问层,数据访问层由EF实现,而非我们自己实现。当然这里的设计还有点瑕疵,稍后会做改进。下面的问题就是,这个控制器依赖于IRepository接口,那么我们应该在哪里初始化这个接口呢?根据上面在Repository构造方法参数中传入IErrorLogger的经验,我们也可以在控制器的构造方法中传入一个IRepository类型的实例。

这是行得通的,并且构造方法参数注入是最常用的依赖注入方法。

下面有必要介绍一下依赖注入。在介绍依赖注入之前,需要先介绍一下依赖倒置原则(DIP),作为一条设计原则,依赖倒置原则强调高层组件应该依赖于抽象而不是某个具体的实现或功能。例如上面的两个例子,Repository类不依赖于IErrorLogger的具体实现,仅依赖于IErrorLogger这个接口,我们只知道这个接口有一个记录日志的功能,但并不知道它具体是怎么实现的(IErrorLogger是个抽象的概念),只有当我们需要某个记录日志的功能时,才会把实现了IErrorLogger接口的类的实例传递给Repository。ArticleController同样只依赖于IRepository这个抽象接口。控制反转(IoC)就是依赖倒置原则的一个应用,用一段泛化的代码控制更加特定的外部组件的执行。在这里的讨论中,控制反转和依赖注入可以认为是同义词。不过在字面上二者并不总是同义词,控制反转有时会指原则,而依赖注入则代表了原则的应用—即模式。实际上,控制反转历史上曾是基于依赖倒置原则的一个模式。依赖注入这个名词由Martin Fowler提出(【企业应用架构模式】),用来专指控制反转的概念。

控制反转/依赖注入(IoC/DI)作为一种模式,可以让高层次方法不再需要辅助组件的具体引用。注入的过程可以通过3种方式实现,一种是通过被注入方法所在的类的构造方法,前面两个例子都是采用了这种方法;二是通过在被注入方法所在的类中定义一个方法或属性;最后一种是让被注入方法所在的类实现一个接口,接口中提供了辅助组件的具体实现。IoC/DI的目的就是降低组件之间的耦合度(高内聚,低耦合。)现在IoC/DI通常会有专门的框架提供,这些框架也提供了很多高级功能,下面还会介绍。

介绍完了依赖注入,下面继续看这个例子,虽然在ArticleController的构造方法中定义了传入IRepository的方法,但是直到现在还没有在任何地方创建一个实现了IRepository的实例,也就是说直到现在我们看到的IRepository仍然是抽象的。虽然我们已经知道Repository 这个类实现了IRepository接口,并且显而易见我们在控制器中肯定会用到Repository这个类,但是究竟要在哪里创建这个类的实例呢?直接在控制器中创建?那控制器就直接依赖于Repository了,违反依赖倒置原则。这里就要用到一个IoC/DI框架了—Ninject,看起来像个日语词汇,没错,它有忍者的意思,快如闪电!首先需要在项目中安装Ninject,使用NuGet 安装,在NuGet命令行中输入:install-package Ninject.MVC3(没错,是MVC3,虽然我用的是MVC4,但这个包同样支持MVC4。)安装完成以后会在App_Start文件夹中生成一个NinjectWebCommon.cs文件,打开这个文件。这里的代码会在应用程序启动之前执行,下面为我们的IRepository接口注册一个IoC容器,在RegisterServices方法中添加代码:

这段代码的作用就是为IRepository注册一个具体实例Repository,MainContext是建模时定义的一个上下文,继承自DbContext,同时会为Repository传入一个名为LogErrorToFile的错误日志实例(LogErrorToFile实现了IErrorLogger接口中用于记录日志的方法),用于把错误信息记录到文本中(完全可以重新定义一个LogErrorToDB 用于把错误信息记录到数据库,这就是依赖注入的好处,可以根据需要定义任何记录错误日志的方法,而不需要修改Repository的任何代码,即Repository不直接依赖于任何记录日志的具体实现。)当用户向ArticleController发送请求时,Ninject会通过ArticleController 的构造方法传入一个IRepository的具体实现(这里是Repository),从而控制器间接依赖于Repository,如果有必要,将来完全可以重新定义一个IRepository的实现,例如不使用EF的数据访问层(NHibernate?),而不需要修改控制器的任何代码,降低了耦合度,提高了代码的复用性。

前面说了,控制器中的设计还有一点瑕疵,现在来改进一下。上面Articles中的请求逻辑非常简单,从数据库中读取前10条文章,如果有一个很复杂的请求逻辑,可能这里就要写很多代码,那么控制器中的代码就会很长。并且这个请求逻辑可能还会出现在其他地方,那时候就又要写一段重复的代码。所以我们可以考虑把这段代码提出来,单独放到一个类中,这个类就是服务类:

这个服务类同样依赖于IRepository接口,并且同样使用了构造方法参数注入的方式传入一个IRepository的实例。服务层同样不直接依赖于特定的仓储层。那么控制器中的代码就可以修改成这样:

但是追求完美的人可能又会提出一个问题,这里的控制器虽然不直接依赖于特定的仓储层,但是却直接依赖于ArticleService这个类,是不是违反了低耦合的原则呢?确实是这样,这里是采取了一个折中方案。因为服务层是对表现层应用逻辑的封装,服务层的作用就是向表现层暴露模型对象数据,可以认为服务层是表现层的一部分。当然我们也可以定义一个IArticleService接口,让控制器依赖于这个接口,而不是IRepository,那么在Ninject中也就不为IRepository注册实例,而是为IArticleService注册:

IRepository repository=new Repository(new ErrorLogger.LogErrorToFile()); kernel.Bind().To().WithConstructorArgument("repository ", repository);

这同样是不错的设计,如果有一个请求用户数据的控制器UserController,则同样需要依赖于一个IUserService接口,那么也需要在Ninject中注册:

kernel.Bind().To().WithConstructorArgument("repository", repository); 在应用程序中会针对每一个模型建立一个访问该模型的服务,就会产生大量的服务,那么在应用程序启动之前,就需要为每个服务注册一个IoC容器,但是服务的数量再多也是有限的,这并不会影响应用程序的效率(几十几百个服务都不是大问题),因此这种设计要更优秀一点。但是这样代码量就会变大,至于偏向哪一种,完全看个人爱好,如果

追求完美可以考虑这种设计。可能会有人提出来,难道不能定义一个更高级的接口IService 吗?让所有具体的服务接口都继承自这个接口。理论上是可以的,但是前面说了,服务层是对应用逻辑的封装,每个具体服务请求数据的方式都不同,没办法在一个高级接口中涵盖所有情况。好了,这个项目的架构基本完成了。但别忘了,我们用的是https://www.wendangku.net/doc/d218273403.html, MVC4,MVC4新增了一个很有用的功能—WebAPI。让我们来建一个WebAPI看看:

看起来和一般的控制器没什么两样,只是继承自ApiController。执行一下看看会发生什么:

竟然有错。原来Ninject不能直接支持WebAPI。该怎么办呢?我们可以手动让它支持。直接贴代码:

先建一个NinjectWebApiScope类,实现System.Web.Http.Dependencies.IDependencyScope接口:

再建一个NinjectWebApiResolver类,继承自上面的类:

然后修改NinjectWebCommon.cs中的RegisterServices方法:

设置应用程序默认的依赖解析器为我们自定义的解析器。这样就可以了。

面向对象设计之定义领域服务

面向对象设计之定义领域服务 若遵循基于面向对象设计范式的领域驱动设计,并用以应对纷繁复杂的业务逻辑,则强调领域模型的充血设计模型已成为社区不争事实。我将Eric提及的战术设计要素如EnTIty、Value Object、Domain Service、Aggregate、Repository与Factory视为设计模型。这其中,只有EnTIty、Value Object和Domain Service才能表达领域逻辑。 为避免贫血模型,在封装领域逻辑时,考虑设计要素的顺序为: Value Object -》EnTIty -》Domain Service 切记,我们必须将Domain Service作为承担业务逻辑的最后的救命稻草。之所以把Domain Service放在最后,是因为我太清楚领域服务的强大魔力了。开发人员总会有一种惰性,很多时候不愿意仔细思考所谓职责(封装领域逻辑的行为)的正确履行者,而领域服务恰恰是最便捷的选择。 就我个人的理解,只有满足如下三个特征的领域行为才应该放到领域服务中: 领域行为需要多个领域实体参与协作 领域行为与状态无关 领域行为需要与外部资源(尤其是DB)协作 假设某系统的合同管理功能允许客户输入自编码,该自编码需要遵循一定的编码格式。在创建新合同时,客户输入自编码,系统需要检测该自编码是否在已有合同中已经存在。针对该需求,可以提炼出两个领域行为: 验证输入的自编码是否符合业务规则 检查自编码是否重复 在寻找职责的履行者时,我们应首先遵循信息专家模式,即拥有信息的对象就是操作该信息的专家,因此可以提出一个问题:领域行为要操作的数据由谁拥有?针对第一个领域行为,就是要确认谁拥有自编码格式的验证规则?有两个候选: 拥有自编码信息的合同(Contract)对象

领域驱动设计(DDD)架构的实践

领域驱动设计(DDD)架构的实践

前言 至少30年以前,一些软件设计人员就已经意识到领域建模和设计的重要性,并形成一种思潮,Eric Evans将其定义为领域驱动设计(Domain-Driven Design,简称DDD)。在互联网开发“小步快跑,迭代试错”的大环境下,DDD似乎是一种比较“古老而缓慢”的思想。 然而,由于互联网公司也逐渐深入实体经济,业务日益复杂,我们在开发中也越来越多地遇到传统行业软件开发中所面临的问题。本文就先来讲一下这些问题,然后再尝试在实践中用DDD的思想来解决这些问题。 问题 过度耦合 业务初期,我们的功能大都非常简单,普通的CRUD就能满足,此时系统是清晰的。随着迭代的不断演化,业务逻辑变得越来越复杂,我们的系统也越来越冗杂。模块彼此关联,谁都很难说清模块的具体功能意图是啥。修改一个功能时,往往光回溯该功能需要的修改点就需要很长时间,更别提修改带来的不可预知的影响面。

下图是一个常见的系统耦合病例。 订单服务接口中提供了查询、创建订单相关的接口,也提供了订单评价、支付、保险的接口。同时我们的表也是一个订单大表,包含了非常多字段。在我们维护代码时,牵一发而动全身,很可能只是想改下评价相关的功能,却影响到了创单核心路径。虽然我们可以通过测试保证功能完备性,但当我们在订单领域有大量需求同时并行开发时,改动重叠、恶性循环、疲于奔命修改各种问题。 上述问题,归根到底在于系统架构不清晰,划分出来的模块内聚度低、高耦合。

有一种解决方案,按照演进式设计的理论,让系统的设计随着系统实现的增长而增长。我们不需要作提前设计,就让系统伴随业务成长而演进。这当然是可行的,敏捷实践中的重构、测试驱动设计及持续集成可以对付各种混乱问题。重构——保持行为不变的代码改善清除了不协调的局部设计,测试驱动设计确保对系统的更改不会导致系统丢失或破坏现有功能,持续集成则为团队提供了同一代码库。 在这三种实践中,重构是克服演进式设计中大杂烩问题的主力,通过在单独的类及方法级别上做一系列小步重构来完成。我们可以很容易重构出一个独立的类来放某些通用的逻辑,但是你会发现你很难给它一个业务上的含义,只能给予一个技术维度描绘的含义。这会带来什么问题呢?新同学并不总是知道对通用逻辑的改动或获取来自该类。显然,制定项目规范并不是好的idea。我们又闻到了代码即将腐败的味道。 事实上,你可能意识到问题之所在。在解决现实问题时,我们会将问题映射到脑海中的概念模型,在模型中解决问题,再将解决方案转换为实际的代码。上述问题在于我们解决了设计到代码之间的重构,但提炼出来的设计模型,并不具有实际的业务含义,这就导致在开发新需求时,其他同学并不能很自然地将业务问题映射到该设计模型。设计似乎变成了重构者的自娱自乐,代码继续腐败,重新重构……无休止的循环。 用DDD则可以很好地解决领域模型到设计模型的同步、演化,最后再将反映了领域的设计模型转为实际的代码。

[教程]-领域驱动设计(DDD)

本文内容提要: 1. 领域驱动设计之领域模型 2. 为什么建立一个领域模型是重要的 3. 领域通用语言(Ubiquitous Language) 4.将领域模型转换为代码实现的最佳实践 5. 领域建模时思考问题的角度 6.领域驱动设计的标准分层架构 7. 领域驱动设计过程中使用的模式 关联的设计 实体(Entity) 值对象(Value Object) 领域服务(Domain Service) 聚合及聚合根(Aggregate,Aggregate Root) 工厂(Factory) 仓储(Repository) 8. 设计领域模型的一般步骤 9. 领域驱动设计的其他一些主题 10. 一些相关的扩展阅读 领域驱动设计之领域模型 2004年Eric Evans发表Domain-Driven Design – Tackling Complexity in the Heart of Software (领域驱动设计),简称Evans DDD。领域驱动设计分为两个阶段: 1. 以一种领域专家、设计人员、开发人员都能理解的―通用语言‖作为相互交流的工具,在不断交流的过程中不断发现一些主要的领域概念,然后将这些概念设计成一个领域模型; 2. 由领域模型驱动软件设计,用代码来表现该领域模型。 由此可见,领域驱动设计的核心是建立领域模型。领域模型在软件架构中处于核心地位;软件开发过程中,必须以建立领域模型为中心。 为什么建立一个领域模型是重要的 领域驱动设计告诉我们,在通过软件实现一个业务系统时,建立一个领域模型是非常重要和必要的,因为领域模型具有以下特点: 1. 领域模型是对具有某个边界的领域的一个抽象,反映了领域内用户业务需求的本质;领域模型是有边界的,只反应了我们在领域内所关注的部分;

领域知识模型

领域知识模型——企业应用系统的智慧中枢 摘要:企业应用系统有海量的领域对象和丰富的领域知识,这些领域知识一般被作为领域对象的业务逻辑或规则定义。本文认为领域知识是领域模型的一个知识切面且自成体系,结合领域驱动设计[DDD]和面向方面编程[AOP]的方法,对领域知识进行建模和应用,让面向业务活动的领域应用对象只需关注业务过程的组织和管理,用AOP技术把领域知识应用到具体的业务处理策略中,使领域应用对象和领域知识对象有更好内聚性且更轻量,不仅可大幅提升它们的可管理性和复用性,而且对系统开发效率、动态业务建模和装配能力也大有益处。 关键词:领域知识、领域模型、领域驱动设计、企业应用架构、DDD、AOP 1.前言 领域模型[Domain Model]和领域驱动设计[Domain-Driven Design][1]是目前在应用软件行业非常热门和前沿的话题,普遍认为这是构建高质量复杂系统最有效的方法和技术。领域模型在业界比较认可的定义是:领域模型是领域内的概念或者现实世界中对象的可视化表示,又称为概念模型、领域对象模型、分析对象模型,它专注于分析领域问题本身,领域对象是与技术无关的纯业务对象。领域建模的核心理念是把业务对象的属性、规则和职能封装在领域对象中,而不是被分散在用户界面层、应用层和持久化层中。 领域建模一般情况下是从应用功能或用例[Use Case]入手,因此,领域模型中的领域对象也是直接与应用功能或用例相关的业务对象,而这些领域对象模型涉及的领域知识,一般都作为领域对象的逻辑或者规则而存在。知识是应用领域问题的本质,是特定领域中一系列业务对象共有的知识切面,这个知识切面自成体系,本文中把这个知识体系的模型称为领域知识模型,与具体应用功能或者活动相关的领域对象模型称为领域应用模型。为了便于理解这些概念,我用一个与企业管理无关的通俗的例子来说明知识模型和应用模型的关系,比如对我喜欢的台球运动进行游戏建模,美式九球模型或者英式斯诺克模型是具体的领域应用模型,球台、球、球杆、运动员等是应用领域模型的核心领域对象,但要做出好玩的仿真游戏,台球碰撞中的基本物理知识是不可或缺的,用牛顿理论作为领域知识模型就涉及到质量、速度、动量等概念和动量守恒及能量守恒模型。知识模型是高度抽象并且可独立存在的模型,也是可以在各种业务情景中复用的模型,就如前面提到的台球游戏用到的牛顿理论模型,同样可以应用到保龄球游戏以及任何一款涉及到碰撞的游戏场景。企业管理领域也同样存在大量的知识模型,本文笔者致力于把企业管理领域涉及的领域知识进行分离、建模和应用的可行性分析和实践,希望以此进一步提升大型复杂企业应用系统的质量、动态业务建模和装配能力及组件复用水平。 2.企业应用系统中的领域知识问题分析 企业应用系统已逐渐成为企业经营管理的一体化应用平台,面向业务流程的行业深度应用

DDD领域驱动设计基本理论知识总结

?领域驱动设计之领域模型 ?为什么建立一个领域模型是重要的 ?领域通用语言(UBIQUITOUS LANGUAGE) ?将领域模型转换为代码实现的最佳实践 ?领域建模时思考问题的角度 ?领域驱动设计的经典分层架构 ?用户界面/展现层 ?应用层 ?领域层 ?基础设施层 ?领域驱动设计过程中使用的模式 ?所有模式的总揽图 ?关联的设计 ?实体(Entity) ?值对象(Value Object) ?领域服务(Domain Service) ?应用层服务 ?领域层服务 ?基础层服务 ?聚合及聚合根(Aggregate,Aggregate Root) ?聚合有以下一些特点: ?如何识别聚合? ?如何识别聚合根? ?工厂(Factory) ?仓储(Repository) ?设计领域模型的一般步骤 ?在分层架构中其他层如何与领域层交互 ?对于会影响领域层中领域对象状态的应用层功能 ?关于Unit of Work(工作单元)的几种实现方法 ?对于不会影响领域层中领域对象状态的查询功能 ?为什么面向对象比面向过程更能适应业务变化 ?领域驱动设计的其他一些主题 ?一些相关的扩展阅读 ?CQRS架构 ?Event Sourcing(事件溯源) ?DCI架构 ?四色原型分析模式 ?时刻-时间段原型(Moment-Interval Archetype) ?参与方-地点-物品原型(Part-Place-Thing Archetype)?描述原型(Description Archetype) ?角色原型(Role Archetype) 领域驱动设计之领域模型

加一个导航,关于如何设计聚合的详细思考,见这篇文章。 2004年Eric Evans 发表Domain-Driven Design –Tackling Complexity in the Heart of Software (领域驱动设计),简称Evans DDD。领域驱动设计分为两个阶段: 以一种领域专家、设计人员、开发人员都能理解的通用语言作为相互交流的工具,在交流的过程中发现领域概念,然后将这些概念设计成一个领域模型; 由领域模型驱动软件设计,用代码来实现该领域模型; 由此可见,领域驱动设计的核心是建立正确的领域模型。 为什么建立一个领域模型是重要的 领域驱动设计告诉我们,在通过软件实现一个业务系统时,建立一个领域模型是非常重要和必要的,因为领域模型具有以下特点: 1.领域模型是对具有某个边界的领域的一个抽象,反映了领域内用户业务需求的本质;领 域模型是有边界的,只反应了我们在领域内所关注的部分; 2.领域模型只反映业务,和任何技术实现无关;领域模型不仅能反映领域中的一些实体概 念,如货物,书本,应聘记录,地址,等;还能反映领域中的一些过程概念,如资金转 账,等; 3.领域模型确保了我们的软件的业务逻辑都在一个模型中,都在一个地方;这样对提高软 件的可维护性,业务可理解性以及可重用性方面都有很好的帮助; 4.领域模型能够帮助开发人员相对平滑地将领域知识转化为软件构造; 5.领域模型贯穿软件分析、设计,以及开发的整个过程;领域专家、设计人员、开发人员 通过领域模型进行交流,彼此共享知识与信息;因为大家面向的都是同一个模型,所以 可以防止需求走样,可以让软件设计开发人员做出来的软件真正满足需求; 6.要建立正确的领域模型并不简单,需要领域专家、设计、开发人员积极沟通共同努力, 然后才能使大家对领域的认识不断深入,从而不断细化和完善领域模型; 7.为了让领域模型看的见,我们需要用一些方法来表示它;图是表达领域模型最常用的方 式,但不是唯一的表达方式,代码或文字描述也能表达领域模型; 8.领域模型是整个软件的核心,是软件中最有价值和最具竞争力的部分;设计足够精良且 符合业务需求的领域模型能够更快速的响应需求变化; 领域通用语言(UBIQUITOUS LANGUAGE) 我们认识到由软件专家和领域专家通力合作开发出一个领域的模型是绝对需要的,但是,那种方法通常会由于一些基础交流的障碍而存在难点。开发人员满脑子都是类、方法、算法、模式、架构,等等,总是想将实际生活中的概念和程序工件进行对应。他们希望看到要建立哪些对象类,要如何对对象类之间的关系建模。他们会习惯按照封装、继承、多态等面向对象编程中的概念去思考,会随时随地这样交谈,这对他们来说这太正常不过了,开发人员就是开发人员。但是领域专家通常对这一无所知,他们对软件类库、框架、持久化甚至数据库没有什么概念。他们只了解他们特有的领域专业技能。比如,在空中交通监控样例中,领域专家知道飞机、路线、海拔、经度、纬度,知道飞机偏离了正常路线,知道飞机的发射。他们用他们自己的术语讨论这些事情,

《领域驱动设计》基础知识汇总

《领域驱动设计》基础知识汇总(转) 1. 什么是领域(Domain) 我们所做的软件系统的目的都是来解决一系列问题,例如做一个电商系统来在线销售自己 企业的产品;做一个灰度发布平台来提升服务的质量和稳定性。任何一个系统都会属于某 个特定的领域,例如: ?论坛是一个领域:要做一个论坛,那这个论坛的核心业务是确定的:比如用户发帖、回 帖等核心基本功能; ?电商系统是一个领域:只要是电商领域的系统,那核心业务就是:商品浏览、购物车、 下单、减库存、付款交易等核心环节; 同一个领域的系统都具有相同的核心业务,因为他们要解决的问题的本质是类似的。因此 可以推断:一个领域本质上可以理解为一个问题域。只要确定了系统所属的领域,那么这个系统的核心业务,即要解决的关键问题就基本确定了。通常我们说,要成为一个领域的 专家,必须要在这个领域深入研究很多年才行,只有这样才会遇到非常多的该领域的问题,积累了丰富的经验。 2.界限上下文(Bounded Context) 通常来说,一个领域有且只有一个核心问题,我们称之为该领域的『核心子域』。在核心 子域、通用子域、支撑子域梳理的同时,会定义出子域中的『限界上下文』及其关系,用 它来阐述子域之间的关系。界限上下文可以简单理解成一个子系统或组件模块。 例如:下图是对酒店管理的子域和界限上下文的梳理:

3. 领域模型(Domain Model) 领域驱动设计(Domain-Driven Design)分为两个阶段: 1.以一种领域专家、设计人员、开发人员都能理解的通用语言作为相互交流的工具,在交 流的过程中发现领域概念,然后将这些概念设计成一个领域模型; 2.由领域模型驱动软件设计,用代码来实现该领域模型; 由此可见,领域驱动设计的核心是建立正确的领域模型。领域模型具有以下特点: 1.对具有某个边界的领域的一个抽象,反映了领域内用户业务需求的本质。它属于『解 决问题空间』。领域模型是有边界的,只反应了我们在领域内所关注的部分,包括实体概 念(如:货物,书本,应聘记录,地址等),以及过程概念(如:资金转账等); 2.提高软件的可维护性,业务可理解性以及可重用性。领域模型确保了我们的软件的业 务逻辑都在一个模型中,帮助开发人员相对平滑地将领域知识转化为软件构造; 3.贯穿软件分析、设计、开发的整个过程。领域专家、设计人员、开发人员面向同一个 模型进行交流,彼此共享知识与信息,所以可以防止需求走样,让软件开发人员做出来的 软件真正满足需求;要建立正确的领域模型并不简单,需要领域专家、设计、开发人员积 极沟通共同努力,然后才能使大家对领域的认识不断深入,从而不断细化和完善领域模型; 4.为了让领域模型看的见,使用的常用表达领域模型的方式:图、代码或文字; 5.重要性:领域模型是整个软件的核心,是软件中最有价值和最具竞争力的部分;设计足 够精良且符合业务需求的领域模型能够更快速的响应需求变化; 4. 领域通用语言 由软件专家和领域专家合作开发一个领域的模型是有必要的。开发过程中,开发人员以类、算法、设计模式、架构等进行思考与交流。但领域专家对此一无所知,他们对技术上的术 语没有太多概念,只了解特有的领域专业技能,例如:在空中交通监控样例中,领域专家 知道飞机、路线、海拔、经度、纬度,他们有自己的术语来讨论这些事情。软件专家和领 域专家交流过程中,需要做翻译才能让对方理解这些概念。 领域驱动设计的一个核心原则是使用一种基于模型的语言。使用模型作为语言的核心骨架,要求团队在进行所有的交流是都使用一致的语言,在代码中也是这样,这种语言被称为 『通用语言』 5.建模思考的问题:用户需求 『用户需求』不能等同于『用户』,捕捉『用户心中的模型』也不能等同于『以用户为核 心设计领域模型』。设计领域模型时不能以用户为出发点去思考问题,不能老想着用户会 对系统做什么;而应该从一个客观的角度,根据用户需求挖掘出领域内的相关事物,思考 这些事物的本质关联及其变化规律作为出发点去思考问题。 领域模型是排除了人之外的客观世界模型,包含了人所扮演的参与者角色。但是一般情 况下不要让参与者角色在领域模型中占据主要位置,否则各个系统的领域模型将变得没有 差别,因为软件系统就是一个人机交互的系统,都是以人为主的活动记录或跟踪。例如:?论坛中如果以人为主导,那么领域模型就是:人发帖,人回帖,人结贴,等等; ?货物托运系统中如果以人为主导,就变成了:托运人托运货物,收货人收货物,付款人 付款,等等;

领域驱动设计和开发实战

领域驱动设计和开发实战 背景 领域驱动设计(DDD)的中心内容是如何将业务领域概念映射到软件工件中。大部分关于此主题的著作和文章都以Eric Evans的书《领域驱动设计》为基础,主要从概念和设计的角度探讨领域建模和设计情况。这些著作讨论实体、值对象、服务等DDD的主要内容,或者谈论通用语言、界定的上下文(Bounded Context)和防护层(Anti-Corruption Layer)这些的概念。 本文旨在从实践的角度探讨领域建模和设计,涉及如何着手处理领域模型并实际地实现它。我们将着眼于技术主管和架极师在实现过程中能用到的指导方针、最佳实践、框架及工具。领域驱动设计和开发也受一些架极、设计、实现方面的影响,比如: ?业务规则 ?持久化 ?缓存 ?事务管理 ?安全 ?代码生成 ?测试驱动开发 ?重构 本文讨论这些不同的因素在项目实施的整个生命周期中怎样对其产生影响,还有架极师在实现成功的DDD中应该去寻求什么。我会先列出领域模型应该具备的典型特征,以及何时在企业中使用领域模型(相对于根本不使用领域模型,或使用贫血的领域模型来说)。 文章包括一个贷款处理示例应用,来演示如何将设计立场、以及这里讨论的开发最佳实践,应用在真实的领域驱动开发项目之中。示例应用用了一些框架去实现贷款处理领域模型,比如Spring、Dozer、Spring Security、JAXB、Arid POJOs和Spring Dynamic Modules。示例代码用Java编写,但对大多数开发人员来说,不论语言背景如何,代码都是很容易理解的。 引言 领域模型带来了一些好处,其中有: ?有助于团队创建一个业务部门与IT部门都能理解的通用模型,并用该模型来沟通业务需求、数据实体、过程模型。 ?模型是模块化、可扩展、易于维护的,同时设计还反映了业务模型。 ?提高了业务领域对象的可重用性和可测性。 反过来,如果IT团队在开发大中型企业软件应用时不遵循领域模型方法,我们看看会发生些什么。 不投放资源去建立和开发领域模型,会导致应用架极出现“肥服务层”和“贫血的领域模型”,在这样的架极中,外观类(通常是无状态会话Bean)开始积聚越来越多的业务逻辑,而领域对象则成为只有getter和setter方法的数据载体。这种做法还会导致领域特定业务逻辑和规则散布于多个的外观类中(有些情况下还会出现重复的逻辑)。

在https://www.wendangku.net/doc/d218273403.html,MVC4中使用领域驱动设计

在领域驱动设计中,我们首先会为领域设计模型,且在设计的过程中完全不考虑存储和具体的实现细节。也就是说在设计中,我们把数据库放在了一个次要的位置(其实仍然很重要,只是在设计架构时我们不考虑它)。有了模型以后,下一步就是如何持久化(保存数据),且这里就存在着面向对象方式表示的数据和数据库所使用的基于元组的关系模型之间的不一致(对象-关系阻抗失谐)。如果可以选用面向对象数据库,事情就会容易许多,然而面向对象数据库并没有成为IT界的主流,因此关系型数据库就成为你唯一的选择。之所以会出现基于领域的设计是为了处理真实世界中的复杂性。运用领域驱动设计之后,你要么选用面向对像数据库,要么引入一个O/R映射层。 然而实现领域驱动设计很复杂,甚至可以说以个人之力完全无法实现。幸好现在有很多框架可用,例如Entity Framework(以下简称EF)。使用EF有三种方法:1.数据库优先,即先设计数据库,然后做数据库和面向对象模型的映射;2.模型优先,先用EF自带的设计工具设计模型,然后生成sql脚本,创建数据库;3.代码优先,先使用其他UML工具设计模型,根据模型手动编写模型代码,然后生成sql脚本,创建数据库。目前最流行的是代码优先,因为它最灵活,然而代码优先的工作量很大。而数据库优先的方法和领域驱动设计的思想相悖。所以我选择了模型优先的方法,但在EF4中,使用模型优先是有问题的,它生成的模型都继承自一个名为EntityObject的基类,这个基类包含了访问数据库的方法,这就不支持持久化透明了。幸好在EF4.1以后微软引入了DbContext,用EF4.1的模型优先可以生成支持持久化透明的实体类,不继承任何基类,数据访问由DbContext实现。在VS2012中创建一个https://www.wendangku.net/doc/d218273403.html, MVC4项目,VS2012会自动添加EF5.0的引用,并且在设计模型时会自动生成支持持久化透明的实体类,但在VS2010中要麻烦点,这里不做说明了,因为用了VS2012就完全没有问题了。具体建模过程不做介绍,网上一搜一大堆。下图为模型的一部分: 在传统的三层架构设计中,三层架构分为数据访问层、业务逻辑层和表现层。很多人在自己实现三层架构的时候都会明确的定义DAL、BLL和UI,但在实现的过程中总会有一些误解,例如很多人误把用户操作的流程当成业务逻辑,而数据访问层就是大量的sql语句和连接数据库的操作。实际上,用户的操作流程应该称为应用逻辑,应该放在服务层。我看过很多人设计的三层架构,BLL层几乎没有什么代码,只是简单的对DAL层的调用,复杂的数据访

基于事件驱动的DDD领域驱动设计框架分享(附源代码)

基于事件驱动的DDD领域驱动设计框架分享(附源代码) 补充:现在再回过头来看这篇文章,感觉当初自己偏激了,呵呵。不过没有以前的我,怎么会有现在的我和现在的enode框架呢?发现自己进步了真好!从去年10月份开始,学了几个月的领域驱动设计(Domain Driven Design,简称DDD)。主要是学习领域驱动设计之父Eric Evans的名著:《Domain-driven design:领域驱动设计:软件核心复杂性应对之道》,以及另外一本Martin Flower的《企业应用架构模式》,学习到了不少关于如何组织业务逻辑方面的知识。另外,在这个过程中也接触到了一些开源的架构和一些很好的思想。如:命令查询职责分离(Command Query Responsibility Segregation,简称CQRS),事件驱动架构(Event Driven Architecture,简称EDA),以及四色原型和DCI架构,等等。前面这些知识对我来说是非常宝贵的财富,可以说我能进淘宝,很大程度上也是因为我学习了前面这些知识的原因。在介绍我设计的框架之前,我想先探讨一下以往我们都是如何思考设计OO的系统的。大家都知道,真正的对象应该是不仅有属性,而且有行为的。并且大家也有另外一个共识,那就是为了完成某个任务,各个对象应该会相互协作共同完成这个任务。之前我们在设计一个系统时,往往会先设计好各个对象,明确他们的职责,在这个过程中,

还会考虑如何建立对象之间的关系(依赖、关联、聚合、组合),在这些关系的影响下,我们会认为对象之间应该有主从关系、依赖关系,等等。然后我们所做的这些设计最终的目的是为了能让对象之间能够通过相互协作来共同完成某 个任务。这种方式最核心的设计特色是,我们会通过”对象引用“的方式来实现对象之间的各种关系。这种方式很好,并且我们也已经完全习惯了从对象的职责以及它们之间的关系 的角度去设计对象。但这仅仅体现了一个哲学思想,那就是“物体之间通过直接作用完成某个任务”。我觉得任何两个对象之间的交互有两种形式:1)直接作用,即对象A引用一个对象B,然后A调用B提供的某个方法,以此来完成两个对象之间的协作;2)间接作用,对象A不引用对象B,仅仅包含了一个对象B的唯一标识,当它要和对象B协作时,会发送一个消息给对象B,然后对象B收到该消息后做出响应,从而实现两个对象之间的协作;不管是哪种方式,他们最终的效果是一致的,都可以实现两个对象之间的交互并最终完成某个任务。那么这两种方式各自的优缺点在哪里呢?我个人觉得对于对象引用的方式,其好处就是简单、直观、容易理解,很符合我们平时的设计习惯。但坏处是什么呢?我个人觉得这种方式是形成对象耦合的根本原因,对象A对对象B存在了紧密的耦合,也许你会说,在间接作用的方式下,对象A不也会保留一个对象B的唯一标识吗?没错,但

领域驱动设计和实践

领域驱动设计和实践 引言 软件系统面向对象的设计思想可谓历史悠久,20世纪70年代的Smalltalk 可以说是面向对象语言的经典,直到今天我们依然将这门语言视为面向对象语言的基础。随着编程语言和技术的发展,各种语言特性层出不穷,面向对象是大部分语言的一个基本特性,像C++、Java、C#这样的静态语言,Ruby、Python 这样的动态语言都是面向对象的语言。 但是面向对象语言并不是银弹,如果开发人员认为使用面向对象语言写出来的程度本身就是面向对象的,那就大错特错了。实际开发中,大量的业务逻辑堆积在一个巨型类中的例子屡见不鲜,代码的复用性和扩展性无法得到保证。为了解决这样的问题,领域驱动设计提出了清晰的分层架构和领域对象的概念,让面向对象的分析和设计进入了一个新的阶段,对企业级软件开发起到了巨大的推动作用。 本文主要介绍了领域驱动设计的基本概念、要素、特点,对比了事务脚本和领域模型的特点,最后介绍了我们在软件开发过程中的领域驱动设计实践。 什么是领域驱动设计(DDD) 领域驱动设计事实上是针对OOAD的一个扩展和延伸,DDD基于面向对象分析与设计技术,对技术架构进行了分层规划,同时对每个类进行了策略和类型的划分。 领域模型是领域驱动的核心。采用DDD的设计思想,业务逻辑不再集中在几个大型的类上,而是由大量相对小的领域对象(类)组成,这些类具备自己的状态和行为,每个类是相对完整的独立体,并与现实领域的业务对象映射。领域模型就是由这样许多的细粒度的类组成。基于领域驱动的设计,保证了系统的可维护性、扩展性和复用性,在处理复杂业务逻辑方面有着先天的优势。 领域驱动设计的特点

相关文档
相关文档 最新文档