领域驱动设计:

ddd-domain-events的Python项目详细描述


灵感来自Udi Dahan’s fabulous Domain Events 尤其是通过Domain Driven Design实现 一般最佳做法。

DDD域事件包使您可以轻松地:
  • 应用程序层注册到域事件
  • domain层引发domain事件,以便可以在application层处理这些事件

domain事件是执行线程的本地事件 (通过python的threading.local) 因此是线程特定的。

安装DDD域事件

pip install ddd-domain-events

为什么要考虑使用域事件?

域事件基于Observer Design Pattern,它是 从application layer代码中分离domain layer业务逻辑的便捷方法-特别是当 域代码不应该有infrastructure layer依赖项(例如调用存储库或调用 外部服务)。

换句话说,您的域实体不应访问应用程序层服务- 因此,您的entities可能使用domain eventsapplication services间接通信。

例如,假设您有一个游戏域,其用户实体具有add_points(点数)行为。 每当执行add_points时,明显的预期行为是将提供的点数添加到 特定用户。然而,在我们的示例游戏中,每当用户达到1000点时,她就应该收到“master” 徽章,每当用户达到1000000点,她应该收到“冠军”徽章。

您的应用程序层伪python代码可能如下所示:

user.add_points(10,000)ifuser.has_reached_master_level:# TODO: Send the user a congratulation email...elifuser.has_reached_champion_level:# TODO: Send the user both a congratulation email and a check...

上面的代码是完全正确的-但是,会有更多的操作/选项 是add_points的结果,那么代码将变得越来越麻烦。

使用域事件替代方法,将允许您编写更像此伪代码的代码:

domain_events.register_event(has_reached_master_level_callback)domain_events.register_event(has_reached_champion_level_callback)user.add_points(10,000)

这段代码更简洁,可以说更易于扩展,如下所示:

domain_events.register_event(has_reached_master_level_callback)domain_events.register_event(has_reached_champion_level_callback)# introduce new level...domain_events.register_event(has_reached_intermediate_level_callback)user.add_points(50)

最后但并非最不重要的是,域事件允许您使用较少的方法保持实体的代码更干净 (例如已达到大师级,而已达到冠军级,可以省略)这可能是 相对复杂-因为它们可能要求您在实体中使用附加状态(以便您知道 在最近调用add_points之后,用户已达到当前级别。

使用DDD域事件

在现有应用程序服务中使用域事件可以通过使用Python的^ {STR 1 } $语句< < /强>来轻松实现。

例如:

在应用层的某个地方…

withDomainEvents()asdomain_events:# create a callback to the notify_top_management Application Layer functionhigh_price_volume_callback=DomainEventCallable(OrderEvent.HIGH_VOLUME_PRICE,notify_top_management),# register callback - so it can be triggered from the Domain Layerdomain_events.register_event(high_price_volume_callback)# create Domain Entityorder=Order()# execute a Domain method that might raise the relevant Domain Eventorder.add_order_items(order_items)

在域层的某处…

# Domain entity raises a Domain Event - allowing the Application Layer# to take a relevant action.DomainEvents.raise_event(OrderEvent.HIGH_VOLUME_PRICE,order=self)

工作原理

下面是一个简单的示例,可以帮助您了解如何以及何时选择使用域事件

Step 1: Define a Domain Event Type in your Domain Layer

fromddd_domain_eventsimportDomainEvents,DomainEventCallableclassOrderEvent(Enum):"""Domain Event raised for special order use cases"""HIGH_QUANTITY='HIGH_QUANTITY'HIGH_VOLUME_PRICE='HIGH_VOLUME_PRICE'

步骤2:定义引发域事件的domain实体

classOrderItem:"""OrderItem value object that contains order details for a single item"""def__init__(self,product_id:str,price:float,quantity:int):self.product_id=product_idself.price=priceself.quantity=quantityclassOrder:"""Order entity that contains order items"""HIGH_VOLUME_PRICE=1_000_000HIGH_QUANTITY=10_000def__init__(self):self._order_items=[]@propertydeforder_items(self):fororder_iteminself._order_items:yieldorder_itemdefadd_order_items(self,order_items:List[OrderItem])->None:total_price=0total_quantity=0fororder_iteminorder_items:total_price+=(order_item.price*order_item.quantity)total_quantity+=order_item.quantity# Process the actual business logic related to this method,# which is add OrderItem value objects to this Order Entityself._order_items.append(order_item)# Notify whoever might be interested about high price volume ordersiftotal_price>=self.HIGH_VOLUME_PRICE:DomainEvents.raise_event(OrderEvent.HIGH_VOLUME_PRICE,order=self)# Notify whoever might be interested about high quantity volume ordersiftotal_quantity>=self.HIGH_QUANTITY:DomainEvents.raise_event(OrderEvent.HIGH_QUANTITY,order=self)

步骤3:定义一个应用程序服务注册到域事件

classOrderService:"""Application Service for handling Order related operations"""@classmethoddefcreate_order(cls,order_items:List[OrderItem])->Order:withDomainEvents()asdomain_events:# Create callbacks for 'side effects' that are related to domain logic,# and which should be handled by the Application Layercallbacks=[DomainEventCallable(OrderEvent.HIGH_VOLUME_PRICE,cls.notify_top_management),DomainEventCallable(OrderEvent.HIGH_VOLUME_PRICE,cls.notify_sales_team),DomainEventCallable(OrderEvent.HIGH_QUANTITY,cls.notify_inventory_team)]# Register for these domain eventsforcallbackincallbacks:domain_events.register_event(callback)order=Order()order.add_order_items(order_items)returnorder@staticmethoddefnotify_sales_team(order:Order)->None:"""A callback for notifying the sales team about the important order"""@staticmethoddefnotify_top_management(order:Order)->None:"""A callback for notifying the top management about the important order"""@staticmethoddefnotify_inventory_team(order:Order)->None:"""A callback for notifying the inventory team required quantities"""

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
java安卓,如何从一个私有的内部类更新视图元素,这个类是一个异步任务   如果代码中没有数字,则返回true的java方法   java是否将liferay service builder数据放入api?   java如何在javafx中显示单元格中的字符串数组   javascript如何从另一个GUI类获取变量?   创建多个对象后的java REST API POST响应?   java中静态块中声明的变量的范围是什么?   jsp Java,Spring MVC,从服务器中提取任何类型的文件(.png,.jpg,.pdf,.doc等)并提供给用户下载的最简单方法?   java应用程序运行在其他应用程序之上   java正则表达式匹配字符串是否应包含“;”特定字符串前后   C++的java原生源代码。awt。机器人   用于访问/共享单个目录的java多个Xodus应用程序   java将方法传递给另一个活动   java如何获取Struts 2中XWWWForMurlen编码的contenttype的参数