精华内容
下载资源
问答
  • 依稀记得我第一次设计一个系统的时候,画了一堆UML(Unified Modeling Language,统一建模语言)图,面对Class Diagram(其实就是领域模型),纠结了好久,不知道如何落地。因为,如果按照这个类图去落数据库的话,...

    依稀记得我第一次设计一个系统的时候,画了一堆UML(Unified Modeling Language,统一建模语言)图,面对Class Diagram(其实就是领域模型),纠结了好久,不知道如何落地。因为,如果按照这个类图去落数据库的话,看起来很奇怪,有点繁琐。可是不按照这个类图落库的话,又不知道这个类图画了有什么用。

    扪心自问,你有多久没有画数据模型和领域模型了?

    现在回想起来,我当时的纠结源自于我对领域模型和数据模型这两个重要概念的不清楚,先前看过DDD(领域驱动设计),里面一句话我觉得讲的很不错,一个类型可以充当多个角色,这个角色可以是显式的(实现了某个接口或基类),也可以是隐式的(承担的具体职责和上下文决定)。

    但是每次在新的需求下来,出设计方案的时候在数据模型和领域模型上会耽误一些时间,根本原因在于对这两个概念混淆。也因为如此,在设计方案或者在开发过程中会频繁修改数据模型的设计,因为如果底层的逻辑、概念、理论基础没搞清楚的话,其构建在其上的系统也会出现问题,非常严重的问题。

    借鉴DDD(领域驱动设计)的一些设计原则,我觉得有必要花时间认真明晰这两个概念,帮助大家在工作中,更好的做设计决策。

    一 概念定义

    数据模型:面向持久化,数据的载体。关注的是领域知识,是业务领域的核心实体,体现了问题域里面的关键概念,以及概念之间的联系。领域模型建模的关键是看模型能否显性化、清晰的表达业务语义,扩展性是其次。


    领域模型:面向业务,行为的载体。关注的是数据存储,所有的业务都离不开数据,都离不开对数据的CRUD,数据模型建模的决策因素主要是扩展性、性能等非功能属性,无需过分考虑业务语义的表征能力。

    一个强调的是实体,另一个强调的是关系,再细想下我们当初建模的时候都是用啥的啥图-ER图,这下子就被慢慢带偏了。设计的数据模型里面带了实体声明也带了业务关系,两者开始混淆。

    是的,二者的确有一些共同点,有时候领域模型和数据模型会长的很像,甚至会趋同,这很正常。但更多的时候,二者是有区别的。正确的做法应该是有意识地把这两个模型区别开来,分别设计,因为他们建模的目标会有所不同。

    如下图所示,数据模型负责的是数据存储面向DB,其要义是扩展性、灵活性、性能。而领域模型负责业务逻辑的实现,其要义是业务语义显性化的表达,以及充分利用OO的特性增加代码的业务表征能力。

    途中标识灰色的部分其实还可以细分,业务到模型之间也可进行拆分,涉及到一些命名,这里就不做展开。感兴趣的可以查阅:PO、VO、DAO、BO、DTO、POJO能分清吗?

    在日常开发过程中,我们在很多的系统业务设计上,并没很好的处理数据模型和领域模型的关系,反而在设计的时候一个是把数据模型当领域模型,另一个是把领域模型当数据模型。

    二 错把领域模型当数据模型

    最近在优化低代码那块的元数据优化,里面涉及到一些元数据存储、拓展问题。这块逻辑大致可以简单概括:

    数据表单设计时候,用户可以动态配置列的属性以及对列属性根据对应的数据类型动态匹配相应函数。

    对于这个规则,领域模型很简单,就是提供了列基本配置信息和属性配置信息配置数据,如下图所示:

    如果按照这个思路下去就会存在两张表meta_field_definition、meta_field_attribute 两张数据表,一张用来存储列的基础定义,另一张用来定义列的属性配置以及拓展。

    如果我们这个干了,我们就犯了把领域模型当数据模型的错误,这里设计一张数据表足够。在原来的元数据列定义表里面加属性配置字段fd_attribute 以Json的形式存储,再基础表单的基础上加拓展表fd_extend_feature(当前业务用不上作为基础保留的拓展字段)

    调整后有什么好处:

    • 首先,一张表单的维护成本肯定比多张表的维护成本低
    • 其次,其数据的扩展性更好。比如:针对某种数据类型要支持某种定制的业务配置和函数支持,如果是一张表,我们就需要往属性表里面继续添加新的业务支持配置。但是如果我们修改为一张表在原有的元数据中保持不变在属性拓展里面以JSON格式添加配置即可。

    可是,在业务代码里面,如果是基于JSON在做事情可不那么美好。我们需要把JSON的数据对象,转换成有业务语义的领域对象,这样,我们既可以享受数据模型扩展性带来的便捷性,又不失领域模型对业务语义显性化带来的代码可读性。

    三 错把数据模型当领域模型

    的确,数据模型最好尽量可扩展,毕竟,改动数据库可是个大工程,不管是加字段、减字段,还是加表、删表,都涉及到不少的工作量。

    拿上面的案例来讲

    可以注意到fd_extend_feature 拓展表所创建的,便于对表的垂直拓展补充。JSON字段也好,垂直表也好,虽然可以很好的解决数据存储扩展的问题,但是,我们最好不要把这些扩展(features)当成领域对象来处理,否则,你的代码根本就不是在面向对象编程,而是在面向扩展字段(features)编程,从而犯了把数据模型当领域模型的错误。更好的做法,应该是把数据对象(Data Object)转换成领域对象来处理。但是在处理改字段的时候,如果频繁操作addFdExtendFeature、getFdExtendFeature是一种典型的把数据模型当领域模型的错误示范。

    四 总结

    在日常设计和开发中我们应该是把领域模型、数据模型区别开来,让他们各司其职,从而更合理的架构我们的应用系统。其中,领域模型是面向领域对象的,要尽量具体,尽量语义明确,显性化的表达业务语义是其首要任务,扩展性是其次。而数据模型是面向数据存储的,要尽量可扩展。

    回归到主题一个类型可以充当多个角色,这个角色可以是显式的(实现了某个接口或基类),也可以是隐式的(承担的具体职责和上下文决定),

    • 数据模型:面向持久化,数据的载体。
    • 领域模型:面向业务,行为的载体。

    【原文地址】:原文跳转
    【欢迎关注】:码农架构

    专注于系统架构、高可用、高性能、高并发类技术分享

    展开全文
  • DDD领域模型 领域模型是对领域内的概念类或现实世界中对象的可视化表示。又称概念模型、领域对象模型、分析对象模型。它专注于分析问题领域本身,发掘重要的业务领域概念,并建立业务领域概念之间的关系。 业务对象...

    DDD领域模型

    领域模型是对领域内的概念类或现实世界中对象的可视化表示。又称概念模型、领域对象模型、分析对象模型。它专注于分析问题领域本身,发掘重要的业务领域概念,并建立业务领域概念之间的关系。

    业务对象模型(也叫领域模型 domain model)是描述业务用例实现的对象模型。它是对业务角色和业务实体之间应该如何联系和协作以执行业务的一种抽象。业务对象模型从业务角色内部的观点定义了业务用例。该模型为产生预期效果确定了业务人员以及他们处理和使用的对象(“业务类和对象”)之间应该具有的静态和动态关系。它注重业务中承担的角色及其当前职责。这些模型类的对象组合在一起可以执行所有的业务用例。

    贫血模型是指领域对象里只有get和set方法(POJO),所有的业务逻辑都不包含在内而是放在Business Logic层。

    img

    优点是系统的层次结构清楚,各层之间单向依赖,Client->(Business Facade)->Business Logic->Data Access Object。可见,领域对象几乎只作传输介质之用,不会影响到层次的划分。

    该模型的缺点是不够面向对象,领域对象只是作为保存状态或者传递状态使用,它是没有生命的,只有数据没有行为的对象不是真正的对象,在Business Logic里面处理所有的业务逻辑,对于细粒度的逻辑处理,通过增加一层Facade达到门面包装的效果。

    在使用Spring的时候,通常暗示着你使用了贫血模型,我们把Domain类用来单纯地存储数据,Spring管不着这些类的注入和管理,Spring关心的逻辑层(比如单例的被池化了的Business Logic层)可以被设计成singleton的bean。

    假使我们这里逆天而行,硬要在Domain类中提供业务逻辑方法,那么我们在使用Spring构造这样的数据bean的时候就遇到许多麻烦,比如:bean之间的引用,可能引起大范围的bean之间的嵌套构造器的调用。

    贫血模型

    贫血模型实施的最大难度在于如何梳理好Business Logic层内部的划分关系,由于该层会比较庞大,边界不易控制,内部的各个模块之间的依赖关系不易管理,可以考虑这样这样的实现思路:

    (1)铺设扁平的原子业务逻辑层,即简单的CRUD操作(含批量数据操作);

    (2)特定业务清晰的逻辑通过Facade层来组装原子操作实现。

    (3)给业务逻辑层实施模块划分,保持模块之间的松耦合的关系。

    举例说明:

    原子业务逻辑层(Service)提供了用户模型的条件查询方法:

    List queryUser(Condition con)

    Facade层则提供了一种特定的业务场景的分子接口,满足18岁的中国公民,内部实现调用的正是上述的原子接口:

    List queryAdultChinese()

    Facade、Service层纵向划分为几个大的领域包:用户、内容和产品。

    充血模型

    充血模型层次结构和上面的差不多,不过大多业务逻辑和持久化放在Domain Object里面,Business Logic只是简单封装部分业务逻辑以及控制事务、权限等,这样层次结构就变成Client->(Business Facade)->Business Logic->Domain Object->Data Access Object。

    img

    它的优点是面向对象,Business Logic符合单一职责,不像在贫血模型里面那样包含所有的业务逻辑太过沉重。

    缺点是如何划分业务逻辑,什么样的逻辑应该放在Domain Object中,什么样的业务逻辑应该放在Business Logic中,这是很含糊的。即使划分好了业务逻辑,由于分散在Business Logic和Domain Object层中,不能更好的分模块开发。熟悉业务逻辑的开发人员需要渗透到Domain Logic中去,而在Domian Logic又包含了持久化,对于开发者来说这十分混乱。 其次,如果Business Logic要控制事务并且为上层提供一个统一的服务调用入口点,它就必须把在Domain Logic里实现的业务逻辑全部重新包装一遍,完全属于重复劳动。

    使用RoR开发时, 每一个领域模型对象都可以具备自己的基础业务方法,通常满足充血模型的特征。充血模型更加适合较复杂业务逻辑的设计开发。

    充血模型的层次和模块的划分是一门学问,对开发人员要求亦较高,可以考虑定义这样的一些规则:

    (1)事务控制不要放在领域模型的对象中实现,可以放在facade中完成。

    (2)领域模型对象中只保留该模型驱动的一般方法,对于业务特征明显的特异场景方法调用放在facade中完成。

    微服务架构设计基础之领域驱动设计

    DDD(Domain Driven Design)早于微服务「出道」十年,这两个「忘年交」的软件设计哲学是如何相爱相杀的?

    背景

    微服务现在可以说是软件研发领域无人不提的话题,然而业界流行的对比多数都是所谓的Monolithic(单体应用),而大量的系统在十几年前都已经是以SOA(面向服务架构)为基础的分布式系统了,那么微服务作为新的架构标准与SOA有什么差异点呢?其本质区别在于设计原理,微服务是去中心化设计,SOA是「集成」形成中心设计;
    img

    另外,笔者认为以下几点并不是微服务和SOA的区别点:

    • CI/CD:持续集成、持续部署本身与敏捷、DevOps是交织在一起的,CI\CD更倾向于软件工程的领域,与微服务无关;

    • 基于容器还是虚拟机:Docker、虚拟机、物理机等是物理介质的一种实现方式,与微服务无关;

    • 微服务周边生态:比如日志平台、调用链系统?更多的是研发本身对于效率提高的自驱力,而与使用何种架构方式无关;

    • 通讯协议:微服务的推荐通讯协议是RESTful,而传统的SOA是SOAP。不过基于轻量级的RPC框架Dubbo、Thrift、gRPC来实现微服务也很多;在Spring Cloud中也有Feign框架将标准RESTful转为代码的API这种仿RPC的行为,这些通讯协议不是区分微服务架构和SOA架构的核心差别;

      当然,软件工程(DevOps)、基础设施(容器化)、软件开发模式(敏捷开发)的变革有利的推进了微服务架构的大行其道。而微服务架构是一种架构风格、架构理念,其中的「微」更体现了它的精髓在切分。在实际微服务的落地过程中证明,如果切分是错误的,你得不到微服务承诺的「低耦合、自治、易维护」之类的优势,并且还会比单体架构拥有更多的麻烦。那么如何切分呢?其实并不是一些新的方法论,而是都提出很多年的架构设计方法,也称它们为微服务设计基础或架构模型:领域驱动设计和立方体模型。

    领域驱动设计

    2004年,Eric Evans 发表了Domain Driven Design(领域驱动设计,DDD)。领域驱动设计已经问世十几年,从Eric Evans出版的著作「领域驱动设计」一书中对领域驱动做了开创性的理论阐述,在软件设计领域中,DDD可以称得上是步入暮年时期了。遗憾的是,国外软件圈享有盛誉并行之有效的设计方法学,国内大多数的技术人员却并不了解,也未曾运用到项目实践中。直到行业内吹起微服务的热风,人们似乎才重新发现了领域驱动设计的价值,并不是微服务拯救了领域驱动设计,是因为领域驱动设计一直在顽强的成长,其设计开放的设计方法体系,虽然从来不曾在国内大行其道,但却发挥着巨大的价值。表面上看确实是因为微服务,领域驱动设计才又开始出现在大众视野里。

    领域驱动设计的意义

    当然,领域驱动设计并非「银弹」,不是能解决所有疑难杂症的「灵丹妙药」,学习并应用它的意义在于:

    • 一套完整的模型驱动的软件设计方法,用于简化软件项目的复杂度,它能带给你从战略设计到战术设计的规范过程,使得你的设计思路能够更加清晰,设计过程更加规范;
    • 一种思维方式和概念,可以应用在处理复杂业务的软件项目中,加快项目的交付速度;
    • 一组提炼出来的原则和模式,可以帮助开发者开发优雅的软件系统、促进开发者对架构与模型的精心打磨,尤其善于处理系统架构的演进设计、有助于提高团队成员的面向对象设计能力与架构设计能力;
    • 领域驱动设计与微服务架构天生匹配,无论是在新项目中设计微服务架构,还是将系统从单体架构演进到微服务设计,都可以遵循领域驱动设计的架构原则。
      当然,领域驱动能给我们带来很多收获,但如果你是属于以下几种情况的某种,那么你确实不需要学习领域驱动设计了:
      • 如果你是独当一面的架构师,并能设计出优雅的软件架构
      • 如果你是高效编码的程序员,并只想踏踏实实的写代码
      • 如果你是前端的设计人员,并奉行「用户体验至上」的理念
      • 如果你负责的软件系统并不复杂,二三人便可轻松维护

    DDD的关键概念

    一个软件系统的诞生,一定是为了解决我们遇到的某个问题。比如一家企业的一直采用线下销售产品,耗费大量的财力和物力,希望可以在线上销售自己的产品,用于实现在线销售销售产品的目的,那么就诞生了一个电商系统。通常最初设立的目标或要解决的问题就是一个软件项目的出发点,明确我们要做什么。比如一个电商、一个论坛、一个支付平台等。

    下文将从领域、问题域、领域模型、设计、驱动这几个词语的含义和联系的角度去阐述DDD是如何融入到软件开发的。要理解什么是领域驱动设计,首先要理解什么是领域,什么是设计,什么是驱动,什么驱动什么。

    什么是领域/子领域(Domain/Subdomain)

    领域是与某个特定问题相关的知识和行为。比如支付平台就属于特定的领域,只要是这个领域,都会有账户、会记、收款、付款、风控等核心环节。所以,同一个领域的系统都具有相同的核心业务,他们要解决的问题的本质是一致的。一个领域本质上可以理解为就是一个问题域,只要是同一个领域,那问题域就相同。所以,只要我们确定了系统所属的领域,那这个系统的核心业务,即要解决的关键问题、问题的范围边界就基本确定了。

    在日常开发中,我们通常会将一个大型的软件系统拆分成若干个子系统。这种划分有可能是基于架构方面的考虑,也有可能是基于基础设施的。在DDD中,我们对系统的划分是基于领域(基于业务)的。比如上文提到支付平台是一个领域,而账户、会记、收款、付款等则为子领域。一个领域由众多子领域聚集而形成。

    当然,问题随之而来:

    • 哪些概念应该建模在哪些子系统里面?
    • 有时可能会发现一个领域概念建模在子系统A中是可以的,而建模在子系统B中也合情合理。
    • 各个子系统之间的应该如何集成?
    • 有人可能会说,这不简单得就像客户端调用服务端那么简单吗?问题在于,两个系统之间的集成涉及到基础设施和不同领域概念在两个系统之间的翻译,稍不注意,这些概念就会对我们精心创建好的领域模型造成污染。

    DDD中,有标准方法解决上述问题,就是限界上下文(Bounded Context)和上下文映射图。在一个领域/子域中,我们会创建一个概念上的领域边界,在这个边界中,任何领域对象都只表示特定于该边界内部的确切含义。这样的边界便称为限界上下文。限界上下文和领域具有一对一的关系。从物理层面讲,一个限界上下文最终可以是一个Jar/War文件,甚至可以是一个Package中的所有对象。但是,技术本身并不是用来界分限界上下文。
    img

    上图引自《实现领域驱动设计》。通常情况下,一个领域有且只有一个核心问题,我们称之为该领域的「核心域」。在核心域、通用子域、支撑子域梳理的同时,会定义出子域中的「限界上下文」及其关系,用它来阐述子域之间的关系。界限上下文可以简单理解成一个子系统或组件模块。

    什么是设计(Design)

    DDD中的设计主要指领域模型的设计。DDD是一种基于模型驱动开发的软件开发思想,强调领域模型是整个系统的核心,领域模型也是整个平台的核心价值。每一个领域都有一个对应的领域模型,领域模型能够很好的解决负责的业务问题。所以领域模型的设计和架构设计同等重要。

    什么是驱动(Driven)

    DDD中,总是以领域为边界,分析领域中的核心问题(核心关注点)。然后设计对应的领域模型,通过领域模型驱动代码的实现。而数据库设计、持久化技术这些都不是DDD的核心,属于外围的东西。与数据库驱动开发的思路形成对比,驱动中需要记住两个原则:

    • 领域驱动领域模型设计
    • 领域模型驱动代码实现
      领域驱动设计的最大价值是让我们告别从面向过程式的思想(天马星空,想到哪写到哪)转化为基于系统化的模型驱动思维。我们脑补一下软件开发中的常规心路历程:
    • 1、设计表结构
    • 2、写代码(代码写的很冗余,不够抽象)
    • 3、维护代码(适应业务变化)
    • 4、遇到困难(数据结构设计不合理、代码到处冗余、改BUG引入新BUG、新人看代码和无字天书一般)
    • 5、愈发难以维护,开始重构(理论上在老基础上改的技术债务堪比重新开发)
    • 6、重构完成,新系统上线(兼容历史数据、数据迁移、新老系统并行,等等出发点考虑,其实本质上只是做了代码重构)
    • 7、重复执行3-6步…

    DDD的分层架构

    四层架构

    Eric Evans在《领域驱动设计-软件核心复杂性应对之道》这本书中提出了传统的四层架构模式,在后来演进过程中出现了五层架构和六层架构,,如下图所示:
    img

    • User Interface:用户界面层/展示层,负责与用户交互。包含显示信息、解释用户命令等;
    • Application:应用层,用来协调用户与各应用以及各应用之间的交互。不包含业务逻辑、不保存业务对象的状态;
    • Domain:领域层/模型层,负责表达业务概念,业务状态信息以及业务规则。包含领域模型、领域信息、业务对象的状态。领域层是业务软件的核心;
    • Infrastructure:基础设施层,为其他各层提供技术能力。包括为应用层传递消息、为领域层提供持久化机制、为用户界面层绘制屏幕组件等等。基础设施层还能够通过架构框架来支持四个层次间的交互模式。

    六边形架构

    随着后续的演进,出现了一种改进分层架构的方法,即Robert C. Martin提出的依赖倒置原则(Dependency Inversion Principle,DIP)。它通过改变不同层之间的依赖关系达到改进目的。

    • 高层模块不应该依赖于底层模块,两者都应该依赖于抽象
    • 抽象不应该依赖于细节,细节应该依赖于抽象

    根据该原则的定义,DDD分层架构中的低层组件应该依赖于高层组件提供的接口,即无论高层还是低层都依赖于抽象,整个分层架构好像被推平了,再向其中加入了一些对称性,就出现了一种具有对称性特征的六边形架构风格。六边形架构是Alistair Cockburn在2005年提出的,其本质是倡导不同的客户通过「平等」的方式与系统交互,通过不断的扩展适配器转化成系统API所理解的参数来达到每种特定的输出,而每种特定的输出都有适配器完成相应的转化功能。
    img

    聚合:

    • 一组具有内聚关系的相关对象的集合;
    • – 是一个修改数据的最小原子单元;
    • – 聚合通常使用id访问;
    • 实体(Entity):表示具有生命周期并且会在其生命周期中发生改变的东西。含有VO、具有identity的特性,通常具有生命周期的概念 JPA tag @Entity;
    • 值对象(Value Object):表示起描述性作用的并且可以相互替换的概念。类似于pojo,不可变immutable,可在不同模型中传递,Spring tag @value;
    • 领域事件(Domain Event):所有的领域对象的跨聚合变更需要以事件方式进行通知和记录,聚合内的酌情考虑;
    • 工厂(Factory):负责所有对象的生成和组装;
    • 领域服务(Domain Service):纯技术层面的服务,例如日志,或者是跨聚合的编排服务,通常是Spring Component;
    • 资源层(Repository):类似于DAO层,Spring JPA, Hibernate之类 @CRUDRepository;
    • 防腐层:并非是系统间的消息传递机制,它的职责更具体的是指将某个模型或者契约中的概念对象及其行为转换到另一个模型或者契约中;

    贫血模型VS充血模型

    读完上面的两种分层架构方式,可能很多人会有疑问,这些是什么?为什么我之前一直都没听到过这种分法?确实是这样,DDD和面向对象、设计模式等等理论有千丝万缕的联系,如果不熟悉OOA、OOD,那么DDD可能也会理解不了。因为我们大部分从开发生涯开始之初接触的都是「Action层、Service层、Dao层、DB层」这样的MVC分层理论。并且在21中设计模式中,「行为型」的设计模式,我们几乎没有什么机会使用,导致这些问题的原因是J2EE经典分层的开发方式是「贫血模型」。

    Martin Fowler(对,就是提出微服务的那位大牛)曾经提出了两种开发方式,即:

    • 以「贫血模型」为基础的「事务脚本」的开发方式
    • 以「充血模型」为基础的「领域驱动」的开发方式

    贫血模型

    贫血模型是指对象只用于在各层之间传输数据使用,只有数据字段和Get/Set方法,没有逻辑在对象中。而「事务脚本」可以理解为业务是由一条条增删改查的SQL组织而成,是面向过程的编程。

    充血模型是面向对象设计的本质,一个对象是拥有状态和行为的。将大多数业务逻辑和持久化放在领域对象中,业务逻辑只是完成对业务逻辑的封装、事务、权限、校验等的处理。

    举例,用户管理模块大概是这样的两种实现:

    // 贫血模型下的实现

    public class User{

    private Integer id;
    private String name;
    ...
    // 省略get/set方法
    

    }

    public class UserManager{
    public void save(User user){

        // 持久化操作....
    
    }
    

    }

    // 保存用户的操作可能是这样
    userManager.save(user);
    // 充血模型下的实现
    public class User{
    private Integer id;
    private String name;

    // 省略get/set方法

    public void save(){
    
        // 持久化操作....
    
    }
    

    }

    // 保存用户的操作可能是这样
    user.save();
    Martin Fowler定义的「贫血模型」是反模式,面对简单的小系统用事务脚本方式开发没问题;稍微大一些的系统使用事务脚本方式会扩大维护成本,业务逻辑、各种状态散布在大量的函数中,哪怕就是要用户对象中增加一个字段,可能都会涉及到几个类的调整…

    希望领域对象能够准确地表达出业务意图,但是多数时候,我们所看到的却是充满getter和setter的领域对象,此时的领域对象已经不是领域对象了,反模式的贫血对象了。其实在贫血模型和充血模型模型之外,还有失血模型和胀血模型,但后者两个基本是实际开发中不会去使用,因为走的是两个极端。

    总结

    本文宏观角度介绍了领域驱动设计,那么微服务和DDD是什么关系呢?其实在2015年的一次演讲中,DDD的提出者Eric Evans表达了对微服务技术的热爱与支持,认为微服务是让DDD落地的好工具。因为DDD和微服务其本质是降低软件项目的复杂性,而DDD是一种设计理念/设计方法,DDD需要有强制性的原则做保障,否则不同的领域对象终究会混在一起。而微服务本身的一些限制,以及大家都能理解微服务的实施前提和首要条件,会在实现上给DDD增加了一些原则限制。DDD和微服务的不一定要同时使用落地,但是如果将DDD和微服务(两个相差十岁的软件设计方法)结合一起,那么Martin Fowler和Eric Evans两位布道师是会很赞同的。

    展开全文
  • 控制复杂性的关键是有一个好的领域模型,这个模型不应该仅仅停留在领域的表面,而是要透过表象抓住领域的实质结构,从而为软件开发人员提供他们所需的支持。 领域建模是一个参考框架是一种思维方式也是一组优先任务...

    DDD领域驱动设计——Domain Driven Design入门书籍


    控制复杂性的关键是有一个好的领域模型,这个模型不应该仅仅停留在领域的表面,而是要透过表象抓住领域的实质结构,从而为软件开发人员提供他们所需的支持。

    领域建模是一个参考框架是一种思维方式也是一组优先任务,它旨在加速那些必须处理复杂领域的软件项目的开发,用于解释相关活动,并用其来控制复杂性建立一个好的领域模型。领域模型最大的价值是其提供一种通用语言,这种语言可以将领域专家和技术人员联系在一起。

    成功项目的共同特征:有一个丰富的领域模型,并且这个模型在迭代设计的过程中不断演变,并且成为项目不可分割的一部分。

    项目的宏伟目标——交付了能够满足组织后续需求可以不断演进的复杂软件。

    真正决定软件复杂性的是设计方法。

    很多应用程序最主要的复杂性并不在技术上,而是来自领域本身、用户的活动或业务。当这种领域复杂性在设计中没有得到解决时,基础技术的构思再好也无济于事。成功的设计必须系统地考虑软件的这个核心方面。


    第一部分:运用领域模型

    模型:对现实的一种解释,把与解决问题密切相关的方面抽象出来,忽略无关的细节。

    领域:用户应用软件的问题区域。

    领域模型并非某种特殊的图,而是这种图所传达的思想。是对领域专家头脑中的知识严格的组织且有选择的抽象。

    模型在领域驱动设计中的作用

    1. 模型和设计的核心相互影响

      正是模型与实现之间的紧密联系才使模型变得有用,并确保我们在模型中所进行的分析能够转化为最终产品(即一个可运行的程序)。模型与实现之间的这种紧密结合在维护和后续开发期间也会很有用,因为我们可以基于对模型的理解来解释代码。

    2. 模型是团队所有成员使用的通用语言的中枢

      由于模型与实现之间的关联,开发人员可以使用该语言来讨论程序。他们可以在无需翻译的情况下与领域专家进行沟通。而且,由于该语言是基于模型的,因此我们可借助自然语言对模型本身进行精化。

    3. 模型是浓缩的知识

      模型是团队一致认同的领域知识的组织方式和重要元素的区分方式。透过我们如何选择术语、分解概念以及将概念联系起来,模型记录了我们看待领域的方式。当开发人员和领域专家在将信息组织为模型时,这一共同的语言(模型)能够促使他们高效地协作。模型与实现之间的紧密结合使来自软件早期版本的经验可以作为反馈应用到建模过程中。

    软件的核心:是为用户解决领域相关问题的能力。


    第一章 消化知识

    有效建模的要素

    1. 模型和实现绑定
    2. 建立一种基于模型的语言
    3. 开发一个蕴含丰富知识的模型
    4. 提炼模型
    5. 头脑风暴和实验

    正是头脑风暴和大量实验的创造力才使我们找到了一个富含知识的模型并对它进行提炼,在这个过程中,基于模型的语言提供了很大帮助,而且贯穿整个实现过程中的反馈闭环也对模型起到了“训练”作用。这种知识消化将团队的知识转化为有价值的模型。

    知识消化并非一项孤立的活动,它一般是在开发人员的领导下,由开发人员与领域专家组成的团队来共同协作。他们共同收集信息,并通过消化而将它组织为有用的形式。

    高效率的团队需要有意识地积累知识,并持续学习。对于开发人员来说,这意味着既要完善技术知识,也要培养一般的领域建模技巧(如本书中所讲的那些技巧)。但这也包括认真学习他们正在从事的特定领域的知识。

    领域专家在反复研究所有规则、解决规则之间的矛盾以及以常识来弥补规则的不足等一系列工作中,往往不会意识到他们的思考过程有多么复杂。软件是无法完成这一工作的。正是通过与软件专家紧密协作来消化知识的过程才使得规则得以澄清和充实,并消除规则之
    间的矛盾以及删除一些无用规则。

    更明确的设计具有以下优点:

    1. 为了实现更明确的设计,程序员和其他各位相关人员都必须理解超订的本质,明白它是一个明确且重要的业务规则,而不只是一个不起眼的计算。
    2. 程序员可以向业务专家展示技术工件,甚至是代码,但应该是领域专家(在程序员指导下) 可以理解的,以便形成反馈闭环。

    第二章 交流与语言的使用

    领域模型可成为软件项目通用语言的核心,该模型是一组得自于项目人员头脑中的概念,以及反映了领域深层含义的术语和关系。

    这种基于模型的交流并不局限于UML(统一建模语言)图。为了最有效地使用模型,需要充分利用各种交流手段。基于模型的交流提高了书面文档的效用,也提高了敏捷过程中再度强调的非正式图表和交谈的效用。它还通过代码本身及对应的测试促进了交流。

    Ubiquitous Language 通用语言的词汇包括类和主要操作的名称。语言中的术语,有些
    用来讨论模型中已经明确的规则,还有一些则来自施加于模型上的高级组织原则。最后,团队常常应用于领域模型的模式名称也使这种语言更为丰富。

    模型之间的关系成为所有语言都具有的组合规则。词和短语的意义反映了模型的语义。

    开发人员应该使用基于模型的语言来描述系统中的工件、任务和功能。这个模型应该为开发人员和领域专家提供一种用于相互交流的语言,而且领域专家还应该使用这种语言来讨论需求、开发计划和特性。语言使用得越普遍,理解进行得就越顺畅。

    模型

    1. 将模型作为语言的支柱。确保团队在内部的所有交流中以及代码中坚持使用这种语言。在画图、写东西,特别是讲话时也要使用这种语言。
    2. 通过尝试不同的表示方法(它们反映了备选模型)来消除难点。然后重构代码,重新命名类、方法和模块,以便与新模型保持一致。解决交谈中的术语混淆问题,就像我们对普通词汇形成一致的理解一样。
    3. 要认识到, UBIQUITOUS LANGUAGE的更改就是对模型的更改。
    4. 领域专家应该抵制不合适或无法充分表达领域理解的术语或结构,开发人员应该密切关注那些将会妨碍设计的有歧义和不一致的地方

    UBIQUITOUS LANGUAGE是那些以非代码形式呈现的设计的主要载体,这些包括把整个系统组织在一起的大尺度结构、定义了不同系统和模型之间关系的限界上下文,以及在模型和设计中使用的其他模式。 讨论系统时要结合模型。使用模型元素及其交互来大声描述场景,并且按照模型允许的方式将各种概念结合到一起。找到更简单的表达方式来讲出你要讲的话,然后将这些新的想法应用到图和代码中。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eXfAYASt-1616774287086)(G:\研究方向\DDD领域驱动设计\photo\DDD入门书籍\image-20210326215843737.png)]

    UML图无法传达模型的两个最重要的方面,一个方面是模型所表示的概念的意义,另一方面是对象应该做哪些事情。 图是一种沟通和解释手段,它们可以促进头脑风暴。

    设计的重要细节应该在代码中体现出来。 互为补充的图和文档能够引导人们将注意力放在核心要点上。自然语言的讨论可以填补含义上的细微差别。 务必要记住模型不是图。图的目的是帮助表达和解释模型。

    文档应作为代码和口头交流的补充

    代码是行为明确的,但是并不意味着这些明确的行为背后的意义会被人们准确识别出来。

    文档不应再重复表示代码已经明确表达出的内容。代码已经含有各个细节,它本身就是一种精确的程序行为说明。 其他文档应该着重说明含义,以便使人们能够深入理解大尺度结构,并将注意力集中在核心元素上。当编程语言无法直接明了地实现概念时,文档可以澄清设计意图。

    文档必须深入到各种项目活动中去。判断是否做到这一点的最简单方法,是观察文档与UBIQUITOUS LANGUAGE之间的交互。 文档是用人们(当前)在项目上讲的语言编写的吗?它是用嵌入到代码中的语言编写的吗?

    一段代码所产生的实际行为是不会改变的。但是,方法名称可能会有歧义、会产生误导或者因为已经过时而无法表示方法的本质含义。测试中的断言是严格的,但变量和代码组织方式所表达出来的意思未必严格。好的编程风格会尽力使这种联系直接化,但其仍然主要靠开发人员的自律。编码时需要一丝不苟的态度,只有这样才能编写出“言行全部正确”的代码。

    代码必须基于在编写需求时所使用的统一语言。

    DDD核心思想:在实现、设计和团队交流中使用同一个模型作为基础。

    解释性模型提供了一定的自由度,可以专门为某个特殊主题定制一些表达力更强的风格。领域专家在一个领域中所使用的视觉隐喻通常呈现了更清晰的解释,这可以教给开发人员领域知识, 同时使领域专家们的意见更一致。

    UML图VS解释性模型



    第三章 绑定模型和实现

    领域驱动设计要求一种不同的建模方法

    如果整个程序设计或者其核心部分没有与领域模型相对应,那么这个模型就是没有价值的,软件的正确性也值得怀疑。同时,模型和设计功能之间过于复杂的对应关系也是难于理解的,在实际项目中,当设计改变时也无法维护这种关系。若分析与和设计之间产生严重分歧,那么在分析和设计活动中所获得的知识就无法彼此共享。

    MODEL-DRIVEN DESIGN(模型驱动设计)不再将模型和程序设计分离开,而是寻找一种可以满足这两方面的单一模型.

    模型和设计的绑定需要的是在分析和程序设计阶段都能发挥良好作用的模型。

    软件系统各个部分的设计应该忠实地反映领域模型,以便体现出这二者之间的明确对应关系。我们应该反复检查并修改模型,以便软件可以更加自然地实现模型,即使想让模型反映出更深层次的领域概念时也应如此。我们需要的模型不但应该满足这两种需求,还应该能够支持健壮的UBIQUITOUS LANGUAGE(通用语言) 。

    从模型中获取用于程序设计和基本职责分配的术语。让程序代码成为模型的表达,代码的改变可能会是模型的改变。而其影响势必要波及接下来相应的项目活动。
    完全依赖模型的实现通常需要支持建模范式的软件开发工具和语言,比如面向对象的编程。

    程序员的角度来看,对象真实存在于内存中,它们与其他对象相互联系,它们被组织成类,并且通过消息传递来完成相应的行为。

    软件开发就是设计.

    1. 如果编写代码的人员认为自己没必要对模型负责,或者不知道如何让模型为应用程序服务,那么这个模型就和程序没有任何关联。
    2. 如果开发人员没有意识到改变代码就意味着改变模型,那么他们对程序的重构不但不会增强模型的作用,反而还会削弱它的效果。
    3. 如果建模人员不参与到程序实现的过程中,那么对程序实现的约束就没有切身的感受,即使有,也会很快忘记。
    4. 如果分工阻断了设计人员与开发人员之间的协作,使他们无法转达实现MODEL-DRIVEN DESIGN的种种细节,那么经验丰富的设计人员则不能将自己的知识和技术传递给开发人员。

    MODEL-DRIVEN DESIGN的两个基本要素(即模型要支持有效的实现并抽象出关键的领域知识)已经失去了一个,最终模型将变得不再实用。

    任何参与建模的技术人员,不管在项目中的主要职责是什么,都必须花时间了解代码。任何负责修改代码的人员则必须学会用代码来表达模型。每一个开发人员都必须不同程度地参与模型讨论并且与领域专家保持联系。参与不同工作的人都必须有意识地通过UBIQUITOUS LANGUAGE与接触代码的人及时交换关于模型的想法。


    展开全文
  • DDD领域模型设计

    千次阅读 2021-03-08 11:33:09
    一、DDD领域模型设计概念 DDD的全称为Domain-driven Design,即领域驱动设计; 分层架构:UI层、应用层、领域层、基础设施层; User Interface 负责向用户展现信息,并且会解析用户行为,即常说的展现层。 ...

    一、DDD领域模型设计概念

    DDD的全称为Domain-driven Design,即领域驱动设计;
    分层架构:UI层、应用层、领域层、基础设施层;
    User Interface
    负责向用户展现信息,并且会解析用户行为,即常说的展现层。
    Application Layer
    应用层没有任何的业务逻辑代码,它很简单,它主要为程序提供任务处理。
    Domain Layer
    这一层包含有关领域的信息,是业务的核心,领域模型的状态都直接或间接(持久化至数据库)存储在这一层。
    Infrastructure Layer
    为其他层提供底层依赖操作。
    层结构的划分是很有必要的,只有清晰的结构,那么最终的领域设计才宜用,比如用户要预定航班,向Application Layer的service发起请求,而后Domain Layler从Infrastructure Layer获取领域对象,校验通过后会更新用户状态,最后再次通过Infratructure Layer持久化到数据库中。
    在这里插入图片描述
    1、Java动物对象实例

    public class Dog {
        private int age;
        private String color;
        public int getAge() {
            return age;
        } //吃
        public void eat(Object food) {
            System.out.println("吃...");
        } //睡
        public void rest() {
            System.out.println("睡...");
        }
    }
    

    2、贫血模型的例子

    public class Dog {
        private int age;
        private String color;
        private String status;
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        public String getColor() {
            return color;
        }
        public void setColor(String color) {
            this.color = color;
        }
        public String getStatus() {
            return status;
        }
        public void setStatus(String status) {
            this.status = status;
        }
    public class DogService {
        //吃
        public void eat(Dog dog, Object food) {
            dog.setStatus("吃");
            System.out.println(dog.toString() + food.toString());
        }
        //睡
        public void rest(Dog dog) {
            dog.setStatus("睡觉");
            System.out.println(dog.toString() + " 睡觉觉...");
        }
        public Dog getDog(){
            return new Dog();
        }
    }
    public class DogController {
        public void eat() {
            Object food = new Object();
            DogService ds = new DogService();
            Dog dog = ds.getDog();
            ds.eat(dog, food);
        }
        public void rest() {
            DogService ds = new DogService();
            Dog dog = ds.getDog();
            ds.rest(dog);
        }
    }
    

    Dog类只有针对属性的get,set操作,行为被搬到service类了.这种风格是贫血模型的代表。
    缺点:根据个人代码风格,有的controller类很重,有的service类很重。
    最重要的是如果不具备一定的领域分析的知识,往往建出来的类似Dog的领域类是错误的,甚至会根据经验先建数据库再建领域类。

    二、Domain层实现

    Domain层是具体的业务领域层,是发生业务变化最为频繁的地方,是业务系统最核心的一层,这一层包含了如下一些domain object:entity、value object、domain event、domain service、factory、repository等。
    1.实体类:( Entity)
    领域实体是domain的核心成员,domain entity具有以下三个特征:
    唯一业务标识
    持有自己的业务属性和业务行为
    属性可变,有着自己的生命周期,故实体对象可能和它之前的状态不一样,但有同样的唯一标识,是同一个实体。
    例:狗
    2.值对象( ValueObject)
    内部值是不变的,不存在生命周期;
    例:color、point、money、address
    对象是根据值来确定的,可以在不同实体中使用,值对象通常不可变的
    3.Service
    无状态对象
    当一个属性或行为放在实体、值对象中模棱两可或不合适的时候就需要以Service的形式来呈现;
    例:转账、领域逻辑是动词
    三种模型的复杂度是不一样的,在领域建模选Model模棱两可时,优先选择简单模型原则。模型复杂度顺序 Service > Entity > ValueObject

    三、聚合

    1.聚合-对象的依赖关系;
    2.设计聚合时要考虑一致性.意味着一个客户请求只在一个聚合实例上执行一个命令方法;
    3.聚合设计原则:设计小聚合。大的聚合即便能保证事务的一致性,也依然可能限制系统的性能可伸缩性;
    4.通过唯一标识引用其它聚合。
    聚合之间有依赖关系时不要直接写依赖对象,通过唯一标识来引用。通过标识引用可以将不同限界上下文的分布式领域模型关联起来。
    5,在边界之外使用最终一致性。当一个聚合执行命令方法时,还需要在其它聚合上执行任务,使用最终一致性。一种实用的方法可以支持最终一致性,即一个聚合的命令方法发布的领域事件及时地发布给异步的订阅方。
    6.不要在聚合中注入资源库和领域服务。

    四、领域事件

    1.啥是领域事件?
    领域专家所关心的发生在领域中的一些事件。
    将领域中所发生的活动建模成一系列的离散事件。每个事件都用领域对象来表示…领域事件是领域模型的组成部分,表示领域中所发生的事情;
    首先是解决领域的聚合性问题。DDD中的聚合有一个原则是,在单个事务中,只允许对一个聚合对象进行修改,由此产生的其他改变必须在单独的事务中完成。如果一个业务跨多个聚合对象,领域事件会是一个不错的工具来解决这个问题。通过领域事件的方式可以达到各个组件之间的数据一致性,通过最终一致性取代事务一致性。
    其次领域事件也是一种领域分析的工具,有时从领域专家的话中,我们看不出领域事件的迹象,但是业务需求依然有可能需要领域事件。动态流的事件模型加上结合DDD的聚合实体状态和BC,可以有效进行领域建模。
    2.领域事件的技术实现
    领域事件的技术实现实质上观察者模式的实现。技术的实现都好讲,关键是理解观察者模式在领域建模中的应用场景。
    3.领域事件需要关注的类容。
    一,消息设施最终一致性。
    二,事件存储:
    1),将事件存储作为一个消息队列使用。
    2),检查由模型命令方法的所产生的所有结果的记录
    3),使用事件存储中的数据进行业务预测和分析。、
    4),通过事件存储重一个聚合。
    5),撤销对聚合的操作
    4,转发存储的架构风格。

    五、领域服务

    1、领域服务表示一个无状态的操作,强调一个无状态的操作,状态应该在实体中维护,领域服务处理是无状态的逻辑过程;
    2、实现某个领域的任务,即做的也是领域内的事情,是通用语言的表达。而不是应用服务,应用服务是领域服务的客户方,比如api聚合服务,不应该做领域内的事情。也不是基础设施服务,比如DB或消息基础组件。特别是不能跟现在常用的mvc+s架构中的s(service)层混淆,这种情形下的s,很多时候是持久层接口组装,更像是DDD中的资源库的概念。
    3、先考虑聚合或值对像的建模,不适合,然后才使用领域服务。聚合(实体)和值对像才是最重要的DDD建模对象,如果反而首先使用领域服务,容易导致“贫血领域模型”。既然不适合直接在实体或值对像上建模,也基本说明很多时候涉及到多个实体或值对像。
    那什么时候该使用领域服务呢?
    1.执行一个显著的业务操作过程
    2.对领域对象进行转换
    3.以多个领域对象作为输入进行计算,结果产生一个值对像基本就是跟上面对领域服务概念的理解是一致的。
    领域服务实现是否需要独立接口?
    优点:使用接口表达领域概念,而技术实现可以比较随意,比如放在基础实施层,或者在依赖倒置原则中,放在应用层实现也可以;独立接口有利于解耦,通过依赖注入或工厂可以完全解耦客户端与具体实现
    缺点:得写两个对象代码,特别对于java,还得分两个文件,阅读代码也增加点难度,而很多时候一个接口也只有一个实现;另外一个命名问题,在DDD中领域对象名称(对应语言实现的类)和操作名称(对应函数名)是很重要的,是需要表达通用语言的概念的。但如果定义独立接口,也就是会XXXservice的名字来定义接口,但服务实现用什么命名呢?如果用XXXserviceImpl,那其实也说明可以不需要定义独立接口了。测试领域服务其实测试方面,我觉得没有很多需要关注的,或者说我比较少测试方面的需要。但在测试领域服务一节有句话却比较有意思“我们希望对领域服务进行测试,并且希望从客户端的角度对领域服务进行建模,同时我们希望测试能够反映查领域服务的使用方式”,即通过测试代码,告诉客户端怎么使用领域服务。这其实是测试代码的一个重要的作用,但也经常被我们忽略的。
    注意:领域服务不能过多,那变成贫血模型了。

    六、应用服务层

    应用层通过应用服务接口来暴露系统的全部功能。在应用服务的实现中,它负责编排和转发,它将要实现的功能委托给一个或多个领域对象来实现,它本身只负责处理业务用例的执行顺序以及结果的拼装。通过这样一种方式,它隐藏了领域层的复杂性及其内部实现机制。
    应用层相对来说是较“薄”的一层,除了定义应用服务之外,在该层我们可以进行安全认证,权限校验,持久化事务控制,或者向其他系统发生基于事件的消息通知,另外还可以用于创建邮件以发送给客户等。

    七、构架及架构风格

    一, 架构部分:

    1. 限界上下文、子域:
      领域:通常是指整个系统的业务边界.也可以指子域如核心域等。
      子域:业务系统的某个方面。
      限界上下文:同样的是业务系统中某个方面,它比子域的粒度更小。通常一个子域可以只包含一个限界上下文。
      光看这个,有点绕。但直白点理解,其实它们就是架构中的关于系统/模块的划分。系统可以划分为多个子系统,子系统当然还可以划分为更小的子系统。或者业务模块的划分。
      如果还不够直白,那么如果有微服务经验,可以想想、对照服务的划分。
      2)上下文映射图:
      在这里插入图片描述
      DDD中的图示。个人理解:其实它就是各子系统/模块的依赖关系。比如现在典型电商系统子系统划分 会员系统、商品管理系统、资金系统。。。
      在这里插入图片描述
      商品、资金均依赖于会员系统。基本上资金限界上下文同时也是一个子域。同时它们也各自被划分为了一个微服务系统。

    二,架构风格:
    《实现领域驱动设计》关于架构一章,章节名虽然叫架构,但应该理解成架构风格。就象传统的三层架一样,是一种架构风格。
    1)六边形架构
    在这里插入图片描述
    它并不是真的有六条边.它也叫端口+适配器.端口可以理解成http,socket自定义传输协议、或者某个RPC调用协议等。六边形的内部代表了application和domain层。外部代表应用的驱动逻辑、基础设施或其他应用。内部通过端口和外部系统通信,端口代表了一种协议,以API呈现。
    一个例子:
    在这里插入图片描述
    2) Rest
    RESTful风格的架构将‘资源’放在第一位,每个‘资源’都有一个URI与之对应,可以将‘资源’看着是ddd中的实体;RESTful采用具有自描述功能的消息实现无状态通信,提高系统的可用性;至于‘资源’的哪些属性可以公开出去,针对‘资源’的操作,RESTful使用HTTP协议的已有方法来实现:GET、PUT、POST和DELETE。
    3) CQRS
    CQRS就是平常大家在讲的读写分离,通常读写分离的目的是为了提高查询性能,同时达到读/写的解耦。
    CQRS适用于极少数复杂的业务领域,如果不是很适合反而会增加复杂度;另一个适用场景为获取高性能的服务
    4)事件驱动架构
    事件可能有不同类型,这里主要只关心领域事件。
    在这里插入图片描述
    象不象微服务架构中引入消息中间件来解耦和最终事务一致?
    5)管道和过滤器风格.
    管道过滤器来源于linux命令类似 ps -ef | grep tomcat . | 即管道。ps 处理的结果经过管道符| 作为下一个命令的输入。
    《实现领域驱动设计》中举了个基于事件的发布、订阅的例子来实现管道和过滤器架构风格。事件的发布订阅中心作为管道。事件的发布、订阅方作为过滤器。
    推而广之,考虑基于消息中间件的管道过滤器。

    八、实现

    采用三层结构的架构风格就没有领域相关的类容了吗?
    答案当然是有的,但是不象DDD这样有明确的区分。往往因为程序员没有相关概念或多多思考就容易引发问题。

    public class SearchController {
    private SearchService service;
    @RequestMapping(value="search")
    public List search(String searchStr) {
        service.search(searchStr);
    }
    }
    public class SearchService{
      public List search(String  str){
       if(系统变量=="solor"){
          solorService.search(str)
      }else {
        dbService.search(str);
    }
    }
    }
    

    功能很强大,支持数据检索和solor检索。但是再看,solor检索和数据检索明显不是一个玩意,不应该同时出现在SearchService里。从DDD观点来看,也明显属于不同的领域实现模型。即使在同一个子域里,划分微服务那它也应该是两个微服务实现。显明扩展性不好。
    3.作为六边型架构风格的实现,看看一个开发包的结构图在这里插入图片描述

    展开全文
  • 导读:什么是领域模型?什么又是数据模型?两者可以等同吗?在实际应用中,怎么样才能用好它们?本文介绍领域模型和数据模型的概念定义,并举例说明两者相互混淆的错误用法,分享如何正确地应用它们。 依稀记得我第...
  • 我们在上一篇文章中提到过的DDD领域模型的很多概念如通用语言、界限上下文、实体、值对象、聚合、聚合根、领域事件都是通过事件风暴确定的。现在就开始介绍如果用事件风暴构建领域模型。 事件风暴是一项团队活动,...
  • 2.业务模型(领域模型:Domain model):指业务逻辑中,相关联的数据如何联动协同;领域模型存在于领域层; 衔接数据层与领域层的关键对象是Repository(DAO); Entity(实体对象):实体对象是我们正常业务应该用的...
  • 5、简单实现核心的领域模型,屏蔽无关基础设施和界面,进行单元测试和验证需求。 有效建模的要素: 1、模型和实现的绑定。最初的原型虽然简陋,但它在模型与实现之间建立了早期链接,而 且在所有后续的迭代中...
  • DDD领域模型有必要么?

    千次阅读 2021-01-13 18:51:56
    领域模型的基本概念 文章抽出来的知识点是个人差不多整理的,有更好的请告知,轻喷。 我们先来看看一篇我关注博主的DDD入门文章从零开始的领域驱动设计 entity和value object 实体和值对象 一定的数据冗余,有助...
  • 领域模型关注的是领域知识,是业务领域的核心实体,体现了问题域里面的关键概念,以及概念之间的联系。领域模型建模的关键是看模型能否显性化、清晰的表达业务语义,扩展性是其次。 数据模型关注的是数据存储,所有...
  • 统一建模语言UML(四):领域模型和类图 领域模型 领域模型是对领域内概念类或现实世界中对象的可视化表示,也称为概念模型。是更为完整的业务模型的一个特例。从UML的表示法角度,领域模型被描述为一组没有定义...
  • 领域对象映射到微服务代码模型

    千次阅读 2021-01-21 16:00:24
    先构建领域模型 然后设计微服务 以保证领域模型和微服务的一体性。但在构建领域模型时,我们往往是在业务视角,并且有些领域对象还带业务语言。我们还需要将领域模型作为微服务设计的输入,对领域对象进行设计和...
  • 通过这些层次划分,我们可以明确微服务各层的职能,划定各领域对象的边界,确定各领域对象的协作方式。。 DDD的分层架构如图:从上到下依次是:用户接口层、应用层、领域层和基础层。 那 DDD 各层的主要职责是什么呢...
  • 什么是领域驱动模型? 是一套完整,详尽的方法...**什么是领域模型:为什么要建模;怎么建模才合理;“领域”模型具体指什么。** 为什么要建模 “通用”是建模的第一步。“复用”将模型达成一致。 第一: 把心智模型
  • 文章目录前言一、贫血模型1.介绍2.优点3.缺点4.代码样例二、充血模型1.介绍2.优点3.缺点4.代码样例三、对比分析1....贫血模型是指领域对象里只有get和set方法(POJO),所有的业务逻辑都不包含在内而是放在Busin
  • 通过前面的文章介绍,相信大家对于什么是DDD有了初步的了解,知道它是一种微服务的架构设计方法论,为我们解决如何建立领域模型,如何实现微服务划分等提供了方向和指导。但是对于如何具体落地使用DDD,可能大家还是...
  • 领域驱动模型设计(一)

    千次阅读 2021-03-24 14:35:54
    三层架构的问题? 我们平时的开发流程通常... 采用mvc三层架构的模型开发我们的业务逻辑,所有业务逻辑写在service中,我们的实体通常只作为service操作的数据载体。 下图是三层架构中我们主要的工程结构: 在小
  • DDD(领取驱动设计)系列主题之失血模型,贫血模型与充血模型
  • DDD-领域驱动设计示例

    千次阅读 2021-03-17 14:51:17
    一、DDD概述DDD,即领域驱动设计,核心是不断提炼通用语言并用于与领域专家等团队所有成员交流,并用代码来表达出一个与通用语言一致的领域模型。通用语言:通过团队交流达成共识的能够简单清晰准确传递业务规则的...
  • DDD领域驱动设计:四层架构应用

    千次阅读 2021-12-17 09:49:21
    领域模型(充血模型)注入问题结尾 前言 分层架构是运用最为广泛的一种架构模式,几乎每个软件系统都需要通过分层来隔离不同的关注点,以应对不同需求的变化,并且使得这种变化可以独立进行。 对于分层架构来说,...
  • DDD领域驱动设计实战(六)-领域服务

    千次阅读 2021-01-15 23:33:54
    如何在领域模型中使用领域服务 什么是领域服务 何时应该使用领域服务 从案例学习如何对领域服务进行建模 早期项目成员们在Product中维护了一个Backlogitem实例的集合。这种建模方式使得他们可以计算一个Produc的总...
  • 点击上方“朱小厮的博客”,选择“设为星标”后台回复"书",获取后台回复“k8s”,可领取k8s资料- 前言 -要想深入掌握和了解 DDD 领域驱动设计的核心...
  • java DDD领域驱动

    千次阅读 2020-12-23 17:53:48
    领域驱动设计的概念 大家都知道软件开发不是一蹴而就的事情,我们不可能在不了解产品(或行业领域)的前提下进行软件开发,在开发前通常需要进行大量的业务知识梳理,然后才能到软件设计的层面,最后才是开发。而在...
  • DDD领域驱动设计实战-分层架构及代码目录结构

    千次阅读 热门讨论 2021-01-13 15:38:01
    领域模型和业务逻辑分离出来,并减少对基础设施、用户界面甚至应用层逻辑的依赖,因为它们不属业务逻辑。将一个夏杂的系统分为不同的层,每层都应该具有良好的内聚性,并且只依赖于比其自身更低的层。 传统四层...
  • 而 DDD 的真正价值就是在描述该如何建立这个能够指导开发的 “领域模型” , Domain-Driven Design 其实是一种简称, 其真正想表达的是 Domain Model Driven Design, 即领域模型驱动设计 领域模型 – 业务知识的压缩...
  • 领域驱动设计分为两个阶段:以一种领域专家、设计人员、开发人员都能理解的通用语言作为相互交流的工具,在交流的过程中发现领域概念,然后将这些概念设计成一个领域模型;由领域模型驱动软件设计,用代...
  • java顶层文件结构:理解和浅析VO、DTO、DO(Entity)、PO 把我们之前项目的相关规范做了个总结记录下来,仅供参考,望能有点帮助。
  • 充血模型即领域模型模式。 - 贫血模型 - 贫血模型最早广泛应用源于EJB2,最强盛时期则是由Spring创造,将: “行为”(逻辑、过程); “状态”(数据,对应到语言就是对象成员变量)。 分离...
  • 理清了领域逻辑的优先级,同时促使团队在宏观层次的全局分析阶段能够将设计的注意力放在领域和对领域模型的理解上,满足领域驱动设计的要求。 第二重边界:进入解决方案空间,战略设计获得的限界上下文成为了领域...
  • 软件工程的十大模型

    千次阅读 2021-06-11 12:40:05
    1.软件生命周期模型 软件生命周期由软件定义、软件开发与运维(也称软件维护)3个时期组成,每个时期又进一步划分成若干个阶段。 问题定义:“要解决的问题是什么?”通过对客户的访问调查,系统分析员扼要地写出...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 549,386
精华内容 219,754
关键字:

领域模型