EasyDomain是为领域驱动开发设计的基础类库,主要包括实体对象通用能力支持、基于实体的业务规则验证支持、领域事件支持以及应用服务层基于领域事件的发布订阅模式支持。
根据领域驱动设计中实体的定义,一个实体是一个唯一的东西,每一个实体都有一个唯一的业务身份标识,并且实体具有生命周期,在生命周期内实体的状态会不断发生变化。实体对象的每一次变化都需要使用业务规则进行验证,以保证实体状态的变更是合法有效的。
实体的通用基类 EntityBase 和 ConcurrentEntityBase。
class Order extends EntityBase<Long> { @Override public Boolean validate() { return null; } @Override protected BrokenRuleMessage getBrokenRuleMessages() { return null; } }
class Order extends ConcurrentEntityBase<Long> { @Override public Boolean validate() { return null; } public BrokenRuleMessage getBrokenRuleMessages() { return null; } }
实体具有唯一的身份标识,在生命周期内实体的状态会不断发生变化,实体业务规则类,负责保证在实体对象状态变化的过程中实体数据合法有效,当有异常数据时,能够反馈出异常数据的描述或具体异常字段信息等。
业务规则类的基类 EntityRule
class OrderEntityRule extends EntityRule<Order> { // 1 public OrderEntityRule() { // 2 this.isBlank("pin", OrderBrokenRuleMessages.PIN_IS_EMPTY, ""); // 3 this.addRule("totalPrice", new IRule<Order>() { @Override public boolean isSatisfy(Order model) { return model.getTotalPrice().compareTo(BigDecimal.ZERO) > 0; } }, OrderBrokenRuleMessages.TOTAL_PRICE_ERROR, ""); // 4 this.addRule(new IRule<Order>() { @Override public boolean isSatisfy(Order model) { // 4.1 return model.getOrderItemList().size() > 0 && model.getOrderItemList().size() < 100; } }, OrderBrokenRuleMessages.ORDER_ITEM_ERROR, "", new IActiveRuleCondition<Order>() { // 4.2 @Override public boolean isActive(Order model) { return model.getStatus() == 1; } }); } }
// 5 class OrderBrokenRuleMessages extends BrokenRuleMessage { // 5.1 public static final String PIN_IS_EMPTY = "PIN_IS_EMPTY"; public static final String TOTAL_PRICE_ERROR = "TOTAL_PRICE_ERROR"; public static final String ORDER_ITEM_ERROR = "ORDER_ITEM_ERROR"; @Override protected void populateMessage() { // 5.2 this.getMessages().put(PIN_IS_EMPTY, "用户PIN不能为空"); this.getMessages().put(TOTAL_PRICE_ERROR, "订单总金额不能为0"); this.getMessages().put(ORDER_ITEM_ERROR, "订单商品不能为0且商品数超过100"); } }
class Order extends EntityBase<Long> { // 1 @Override public Boolean validate() { // 1.1 return new OrderEntityRule().isSatisfy(this); } // 2 @Override protected BrokenRuleMessage getBrokenRuleMessages() { // 2.2 return new OrderBrokenRuleMessages(); } }
实体业务规则验证,需要和实体配合一块使用,以实体为中心展开验证,一般一个实体只对应一个实体业务规则EntityRule
在实体类中重写validate()方法,如以上示例中 1.1显示,也可以自行写一个validate()的重载,以便实现更加灵活的EntityRule类管理。
在实体类中,还需要重写getBrokenRuleMessages(),直接返回实体业务规则异常描述类的一个实例,如以上的 2.2,一般情况下,实体业务规则异常描述类,是线程安全的,因此,也可以定义单例模式,在getBrokenRuleMessages()方法中返回单例对象。
public class MainTestClass { @Test public void orderTest() { // 3 Order order = new Order(); // 4 Boolean validate = order.validate(); if (!validate) { // 5 order.getBrokenRules(); // 6 order.aggregateExceptionCause(); // 7 order.throwBrokeRuleAggregateException(); // 8 order.exceptionCause(); // 9 order.throwBrokenRuleException(); } } }
在领域驱动设计中,领域事件是对实体对象,由于某一业务操作导致实体对象状态发生变化的事实的描述。例如,当订单实体调用支付payment() 方法后,订单的状态变成已支付,并产生订单已支付的事件,该事件将交由应用服务层去发布,相关业务组件将会订阅订单已支付事件、并对事件做出相关的响应。
@EventName(value = "OrderPayedEvent", shareTopicName = "") class OrderPayedEvent extends BaseDomainEvent { //还可以有其他的字段 public OrderPayedEvent(long orderId) { this.setBusinessId(String.valueOf(orderId)); } }
class Order extends EntityBase<Long> { private BigDecimal totalPrice = BigDecimal.ZERO; private String comment = ""; private String pin; private int status; private List<OrderItem> orderItemList; @Override public Boolean validate() { return new OrderEntityRule().isSatisfy(this); } @Override protected BrokenRuleMessage getBrokenRuleMessages() { return new OrderBrokenRuleMessages(); } /** * 订单支付业务操作 * * @return 返回订单已支持事件 */ public OrderPayedEvent payment() { this.status = 3; return new OrderPayedEvent(this.getId()); } }
应用服务层,在领域驱动设计分层架构中的角色是用于实现协作、统筹和编排领域模型以及基础设施层的各种业务组件类,以实现相关业务功能。此外,对实体对象的各种操作,都必须经由应用服务层处理,任何其它地方都不能私自处理。应用服务层,也是用于保证实体对象逻辑一致性(强一致,一般指数据库事务)和发布实体对象生成的领域事件的地方。
应用服务层是极容易出现代码坏味道的地方,应用服务层是协作者,不是业务决策者。在该层出现业务决策类的代码段时,需要格外注意。
通过将业务决策代码放回到领域层以及通过发布订阅模式将各业务组件进行解耦,可以使该层清晰职责和结构。
// 1 class OrderApplicationService extends BaseApplication { private IOrderRepository orderRepository; // 2 public OrderApplicationService() { this.initSubscriber(); } public void payment(long orderId) { // 3 Order order = this.orderRepository.findByOrderId(orderId); if (order != null) { // 4 OrderPayedEvent orderPayedEvent = order.payment(); // 5 if (order.validate()) { // 6 this.orderRepository.update(order); // 7 this.publishEvent(orderPayedEvent); } else { // 8 throw order.exceptionCause(); } } } }
class OrderApplicationService extends BaseApplication { private IOrderRepository orderRepository; public OrderApplicationService() { // 1 this.initSubscriber(); } public void payment(long orderId) { //发布OrderPayedEvent事件 } private void initSubscriber() { // 2 this.registerDomainEvent(OrderPayedEvent.class); // 3 this.registerSubscriber(new IDomainEventSubscriber<OrderPayedEvent>() { @Override public Class<OrderPayedEvent> subscribedToEventType() { return OrderPayedEvent.class; } @Override public void handleEvent(OrderPayedEvent aDomainEvent) { //调用发送通知用户支付成功的消息服务 } }, "sendSMS"); // 4 this.registerSubscriber(new IDomainEventSubscriber<OrderPayedEvent>() { @Override public Class<OrderPayedEvent> subscribedToEventType() { return OrderPayedEvent.class; } @Override public void handleEvent(OrderPayedEvent aDomainEvent) { //调用通知库房准备生产服务领域事件对上的注解 } }, "noticeWarehouse"); } }
在领域驱动设计中,基础设施层提供具体技术上的支撑,实体对象数据的数据库持久化,面向查询的数据持久化(ES)、面向缓存的数据刷新(Redis)、外部系统远程接口调用以及发布供外部系统处理的消息等。 基础设施层主要有以下几个特点
class OrderRepository implements IOrderRepository{ @Override public Order findByOrderId(long orderId) { //执行数据库查询,返回领域模型对象 return null; } @Override public void update(Order order) { // 1 // 持久化领域模型数据 } }
领域驱动设计,将一个系统或微服务划分成四层,每一层都是不同的角色,有不同的职责。
上图蓝色线体现了各层之间的调用关系,各层的调用并不会严格的经过每一层。
上图红色线体现了基础设施层和各层之间的依赖关系。
领域模型是整个系统的核心和灵魂,所有其它方面都会围绕领域模型开展。当我们需要了解一个系统的时候 ,一般也会从领域模型做为开端。
我正在学习DDD概念,为了加强我的理解,我正在研究一些现实世界的例子。 我知道一个聚合应该只有一个通过根实体的入口点,一个聚合应该只有一个存储库(如果我完全理解错了,请纠正我) 现在假设有特定类型的消耗品,并且这些消耗品是从配送中心发送的。发送特定类型的消耗品取决于它们的数量,我的意思是,如果其中一个消费者对A型和B型的临界数量为10,并且这些项目的数量低于10,那么配送中心发送A型和B型消耗品。
本文向大家介绍谈一下领域驱动设计相关面试题,主要包含被问及谈一下领域驱动设计时的应答技巧和注意事项,需要的朋友参考一下 主要关注核心领域逻辑。基于领域的模型检测复杂设计。这涉及与公司层面领域方面的专家定期合作,以解决与领域相关的问题并改进应用程序的模型。在回答这个微服务面试问题时,您还需要提及DDD的核心基础知识。他们是: DDD主要关注领域逻辑和领域本身。 复杂的设计完全基于领域的模型。 为了改
本文向大家介绍什么是领域驱动设计(DDD)相关面试题,主要包含被问及什么是领域驱动设计(DDD)时的应答技巧和注意事项,需要的朋友参考一下 专注于核心领域逻辑 在模型上找到综合的设计 不断与领域专家合作,改进应用程序模型并解决与领域相关的问题
null 到目前为止,很容易。如果我们试图将规范应用到存储库,而又不破坏DDD模式或存在性能问题,那么问题就会出现。 应用规范的可能方法: 1)经典方法:在领域层使用领域模型进行规范 null null 3)与2)类似,但将规范作为持久层的一部分 这不起作用,因为域层需要参考规范。它仍将取决于持久层。 我们将在持久层中拥有业务逻辑。这也违反了DDD模式 4)与3类似,但使用抽象规范作为接口 nul
问题内容: 新手CSS问题。我认为一个元素的意思是“填充可用空间”。但是对于一个元素来说似乎并非如此。例如: 然后有两个问题: 是否确切定义了width:auto的含义?CSS规范对我来说似乎很模糊,但是也许我错过了相关的部分。 有没有一种方法可以实现我对输入字段的预期行为-即。像其他块级元素一样填充可用空间? 谢谢! 问题答案: 一个的宽度从其生成属性。默认值是驱动自动宽度的原因。 您可以按照下
Wikipedia 上的定义: 测试驱动开发 (TDD) 是一种以非常短的开发周期不断迭代的软件开发过程:首先开发者对将要实现的功能或者新的方法写一个失败的自动化测试用例,然后就去写代码来通过这个测试用例,最终通过重构代码让一其达到可接受的水准。Kent Beck, 这个技术创造者或者说重新发现者,在2003年声明TDD 鼓励简单的设计和激励信心。 目前你可以应用的几种不同类型的测试: 单元测试