最近在学习领域模型,一直纠结在领域层跟数据库层的划分,网上也查了不少资料,趁这段时间有空,好好总结下!
如何进行逻辑划分:
在软件架构中,最常见的一种架构模式就是层式架构模式,即把一个系统按逻辑上的功能拆分成多个层,层与层之间保持单向依赖关系,每层只依赖于其直接下层,以保证每层的良好封装性和独立性。而层式架构模式最常用的就是:展示层-服务层-数据访问层,应用领域驱动设计(充血模型),服务层还应被进一步拆分为:应用服务层和领域层。
综上所述,每个模块(子系统)又可以拆分成:展示层-应用服务层-领域层-数据访问层四个逻辑层。
重要原则:每层只依赖于其直接下层,层与层之间不能形成循环依赖关系。
问题所在:
领域层跟数据库层关系非常密切,所以我们放在一齐进行论述。两者的关系是:数据访问层依赖于领域层。
先来看看领域层,领域层包含了该模块的领域对象和这些领域对象对应的仓库接口(Repository——对应J2EE设计模式的DAO,为了让设计和开发人员在进行建模的阶段尽量脱离具体技术去进行建模,我们建议使用Repository的模型术语取代DAO这个技术化的出于设计模式的术语),注意,这里包含的是仓库的“接口”,而非实现。对于这样的划分,一直存在着争议,最大的争议点在于:领域层的职责是负责领域业务逻辑处理和封装,不应该把数据访问的相关职责也纳入领域层。下面我们对这种设计进行分析和论述,并提供案例作为理据去论证这种设计的原因。
在现实世界中,完成一个业务,并不需要有所谓“持久化”的操作,但这种模型一旦反映到软件中,“持久化”就变成了必不可少的步骤,我们从两个方面去进行分析:
从领域层本身来看,由于领域对象本身包含了绝大部分的业务逻辑,在一些复杂的业务逻辑中,我们有时候出于性能等因素的考虑,是需要在领域对象被加载到内存后,在其业务逻辑中还需要通过额外的查询去查找完成某个业务所需的数据,而这些数据通常并不是领域对象自身的数据,而可能是从属这个领域对象的其他领域对象的数据,下面举一个例子来说明:
上图是案例系统的出版物管理模块的其中一个主要的领域对象:Pulication——刊物,我们看到,Publication有两个从属的领域对象:PriceItem(历史价格明细)和IssueSchedule(历史出版发行计划),PriceItem保存的是对应Publication在不同时间段的不同销售区域的指定币种的销售价格,IssueSchedule保存的是对于Publication在不同时间段的出版发行计划。现在假设有一个订单业务,需要在某个时间段订阅某Publication,那么,为了计算订单的金额,则必须通过该Publication获取两个关键数据:该Publication在指定区域的指定币种的当前销售价格,以及该Publication在这段时间的发行期数。而这两个数据,均来源于Publication本身,也就意味着,Publication领域对象具有两个职责:获取当前区域指定币种销售价格——getCurrentPriceForCurrency和统计指定时间段的出版期数——countIssues,我们有两种方案去实现这个两个方法:
一、通过ORM工具(Hibernate)对Publication的两个聚合对象集合PriceItem、IssueSchedule进行延迟加载设置,当调用该方法时,就可以不显式的调用Repository,而由ORM自动实现所有从属对象的加载。
二、在两个方法的方法体内,显式的调用Repository接口提供的专有查询方法来获取相应数据,该专有查询方法并不把所有从属对象全部加载到内存,而是通过具体的持久化实现的查询语言(SQL、HQL、XQuery等),把符合条件的数据查询出来,而且,该专有查询方法并不带有任何与具体持久化实现耦合的信息,它只提供抽象,具体实现由数据访问层的领域对象仓库实现类提供。
我们来对比一下两者,前者有两个明显的缺陷:1)从方法的职责上来说,方法只返回符合条件的结果,而这种实现会把所有从属数据(并且包括所有字段)都加载到内存,然后进行筛选,这种做法对内存的损耗是可以非常可观的(试想如果历史数据已经积累了很多年,数据量很大的情况)。2)这种设计(实现)方法是依赖于具体技术的,这就意味着,如果具体技术发生改变,会直接影响到Publication的模型,甚至产生更大的连锁效应。而第二种实现方案恰恰弥补了上述两种严重的缺陷。有人可能会认为,第二种方案的最大缺点是让领域对象与Repository形成了一种双向依赖关系而导致两者无法分开,但我们从本质上分析,第一种方案中,其实领域对象Publication依然无法逃脱其业务逻辑需要查询其从属领域对象这个潜在要求,只不过,第一种方案利用了ORM工具的技术手段,让代码中不需要建立这种显式的依赖而已。所以,从功能上来讲,无论何种实现方案,只要业务上有这样的要求(如上例),领域对象是无法与Repository完全脱离关系的。
综上所述,我们从领域层本身出发,得出的结论是:领域对象与领域对象仓库之间存在着天生的互相依赖关系,这种关系在业务简单的时候可能体现不出来,但随着业务的进展,这种潜在的依赖关系很大机会会出现。因此,无论开始的时候业务是否足够简单,以至于领域对象的业务逻辑并不需要有额外的查询,出于对模型的统一的考虑,还是应该在开始设计的时候,把领域对象仓库接口划入领域层(即使它从职责划分原则上来看并不完全合理,但这世界上通常没有完美的解决方案,只有最适合的解决方案)。
从应用服务层的角度看,对于领域层,应用服务层是其客户程序,因为应用服务层依赖于领域层提供领域对象完成相应服务。正如前面所述,在软件世界中,要完成一个业务,“持久化”几乎必不可少,那么,对于应用服务层来说,单独的使用领域对象或领域对象仓库并没有任何的意义,因为应用服务层如果要使用领域对象,则必须通过领域对象仓库对其进行加载,如果是创建新的领域对象,也必须(绝大部分情况)通过领域对象仓库实现领域对象的持久化。同时,应用服务层使用领域对象仓库的唯一目的就是实现对领域对象的增删改查操作。
综上所述,我们从应用服务层的角度看,对于应用服务层来说,领域对象和领域对象仓库本身就是一体化的东西,无法割裂。
经过上述的详细分析,我们已经有充足的理据支持领域对象与领域对象仓库被统一划入领域层的设计。
我们再来分析数据访问层,前面已经说过,数据访问层是依赖于领域层的,它实际上是为应用服务层提供领域层领域对象仓库的具体实现,通过这样的设计,领域层虽然把数据访问的抽象纳入到其职责范围之内,但依然与具体的数据访问实现细节解藕,只要数据访问的抽象不发生变化,持久化实现发生变化只会影响数据访问层,对其他层是完全透明的。
- 大小: 38.6 KB
分享到:
相关推荐
战略设计关注如何将大系统划分为更小、更自治的领域,每个领域都有自己的领域模型,如子域划分、限界上下文等。战术设计则关注如何在每个领域内构建模型,包括实体、值对象、工厂、仓储、聚合根等设计模式。 在实践...
在这个实例中,“逻辑回归模型实例”可能是指一个实际应用逻辑回归的案例,涵盖了数据预处理、模型训练、参数调优以及模型评估等多个步骤。这通常涉及到以下关键知识点: 1. **数据预处理**:在建立模型之前,通常...
在中台设计中,领域模型扮演着至关重要的角色,因为它们定义了中台服务的核心业务逻辑。通过将业务能力封装在领域模型中,中台可以提供标准化的服务接口,实现业务的快速响应和创新。 5. **战略设计与战术设计**: ...
在DDD中,“模型提炼”是一个重要的环节,它涉及如何从复杂的业务逻辑中抽取出核心领域模型,从而简化系统设计并提高软件质量。 #### 核心领域模型的重要性 在业务系统中,核心领域模型是那些最具价值、最能体现...
在`LogisticRegression逻辑回归模型.py`文件中,开发者可能已经完成了以下步骤: 1. **数据预处理**:加载数据集,处理缺失值,进行特征选择或特征工程,将非数值特征转换为数值类型。 2. **数据划分**:将数据集...
这些构造块是设计和实现领域模型的基本元素,通过它们可以构建一个逻辑清晰、结构层次分明的领域模型。 领域驱动设计的编程实践强调了面向对象分析与设计技术的重要性,它对技术框架进行分层规划,如用户界面/展现...
领域模型不仅帮助我们更好地理解业务逻辑,而且还能促进团队成员之间的有效沟通,确保软件设计与实现能够真正符合业务需求。 #### Martin的分析模式介绍 Eric Evans在其著作《领域驱动设计》中提出了领域驱动设计...
8. **反向工程和建模工具**:一些工具如PlantUML、Visual Paradigm等支持反向工程,可以从现有代码中提取领域模型,同时也可以用来生成UML图,帮助团队更好地理解模型。 9. **UI层设计**:虽然DDD主要关注业务逻辑...
逻辑回归是一种常用的分类算法,虽然名字中有“回归”二字,但它主要用于解决二分类问题,在气象预报、市场分析等领域有广泛的应用。 为了实现这一目标,首先需要确保已经安装了必要的Python库,包括pandas、numpy...
在本文中,我们将探讨域模型的定义、价值、与领域驱动设计(DDD)的关系,以及常见的误区和应用实例。 首先,域模型是“特定问题”的抽象模型,它不局限于具体的解决方案,而是聚焦于理解问题域的本质。这使得域...
逻辑回归模型的系数可以直观地解释每个特征对预测目标的影响,这对于医学领域的应用尤其重要,因为它可以帮助医生理解模型的预测依据。 总之,这个项目涵盖了从数据获取、预处理、模型建立、训练、验证到模型应用的...
例如,在一个电子商务系统中,领域模型可能包括商品、订单、用户等实体,以及价格计算、库存检查等行为。 “领域事件”(Domain Event)是DDD中的另一个重要概念,它是业务操作过程中发生的有意义的事件。例如,当...
服务代表领域模型中的行为或操作,它处理不属于任何实体或值对象的业务逻辑。实体是一个由唯一标识符区分的领域对象,它拥有自己的生命周期,其状态可以随时间改变。值对象则是没有唯一标识符的领域对象,它代表了...
逻辑回归是一种广泛应用于分类问题的统计学方法,尤其在机器学习领域中占据着重要的地位。这个压缩包包含了一个完整的逻辑回归训练与测试的实例,旨在帮助用户理解和实践这一算法。以下将详细介绍其中涉及的关键知识...
**逻辑回归** 逻辑回归是一种广泛应用于分类问题的统计学习方法,尤其在二分类问题中表现突出。尽管其名称中带有“回归”二字...通过实际操作,结合"逻辑回归.ipynb"文件中的内容,你可以进一步提升在这一领域的技能。
Java和C#代码中,你可以看到领域模型类,如实体(Entity)、值对象(Value Object)、聚合根(Aggregate Root)等。这些类封装了业务规则和行为,是业务逻辑的载体。 2. **领域事件**(Domain Event):在源码中,...
DDD则强调建立反映业务领域的模型,将业务规则和逻辑封装在领域模型中,使得设计模型与业务模型保持一致,避免“贫血领域对象”问题。 贫血领域对象是指仅有数据属性而缺乏业务逻辑的对象,这在传统的Action/...
最后,将领域模型转化为代码实现,确保模型的业务逻辑准确无误地体现在软件中。 DDD还包括一系列的模式,如事件风暴、子域划分、战略设计等,帮助开发者处理复杂的业务场景。领域驱动设计不仅关注模型本身,还关注...