Domain Driven Design - Part III
Today we will discuss about Domain Services and Domain Events in DDD in detail.
Domain Services
The Domain Service is used when a certain behavior or operation doesn’t naturally fit within a single entity or value object but is important for the domain. It's an efficient way to encapsulate domain logic that cannot be assigned to a particular entity without violating the single responsibility principle.
Key Characteristics of Domain Services:
Stateless: Domain services should not hold state. They are purely operational, containing business logic and acting on one or more entities.
Domain-Specific: The operations encapsulated in a domain service are specific to the business logic of the domain and cannot exist outside of that domain.
Encapsulation: When a behavior involves multiple entities or value objects and doesn’t naturally fit into one, a domain service is the best place to house that logic.
Decoupling: Domain services allow the domain logic to be separated from infrastructure concerns, meaning they are pure business logic and don’t deal with things like database access or external services.
public class DiscountService {
public BigDecimal applyDiscount(Order order, Discount discount) {
// logic to calculate the price after discount
}
}
Domain Events
A Domain Event represents something that has occurred in the domain that the system cares about. It signals that an important business event has occurred and typically notifies the other parts of the system.
Key Characteristics of Domain Events:
Occurrence: For instance, in the eCommerce context, events like "Order Placed", "Payment Completed", or "Shipment Dispatched" would be domain events.
Immutable: Once a domain event is published, its state should not change. It represents a fact in the past that has already happened.
Propagation: Domain events are often used to notify other bounded contexts or external systems about something that has happened, enabling eventual consistency across the system.
Example:
//Event
public class OrderPlacedEvent {
private final OrderId orderId;
private final CustomerId customerId;
private final LocalDateTime occurred;
public OrderPlacedEvent(OrderId orderId, CustomerId customerId) {
this.orderId = orderId;
this.customerId = customerId;
this.occurredOn = LocalDateTime.now();
}
}
//Handler
public class OrderPlacedEventHandler {
public void handle(OrderPlacedEvent event) {
// Access the information from the event
// Send Email to customer order is confirmed
}
}
Here is how to use push events:
public class OrderService {
private final EventPublisher eventPublisher; // Assume this is injected for publishing events
public OrderService(EventPublisher eventPublisher) {
this.eventPublisher = eventPublisher;
}
// Domain service method for placing an order
public void placeOrder(Order order) {
// Business logic to process the order
validateOrder(order);
OrderPlacedEvent event = new OrderPlacedEvent(order.OrderId, order.CustomerId);
eventPublisher.publish(event); // Publishing the event to notify other systems
}
private void validateOrder(Order order) {
// Validate logic here
}
}
If you missed the first and second part of this DDD series you can check the first part here.
Thank you so much for reading this. See you next week!