domain-driven-design
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseDomain-Driven Design
领域驱动设计(Domain-Driven Design,DDD)
Core Concepts
核心概念
Ubiquitous Language
通用语言(Ubiquitous Language)
Use the same terminology as domain experts. Code should read like business documentation.
使用与领域专家一致的术语体系,代码应具备业务文档级的可读性。
Bounded Context
限界上下文(Bounded Context)
A boundary within which a particular domain model is defined and applicable.
定义特定领域模型的适用边界,模型仅在该边界内有效。
Context Map
上下文映射(Context Map)
Shows how bounded contexts relate to each other.
展示不同限界上下文之间的关联关系。
Building Blocks
构建块
Entity
Entity(实体)
Has identity that persists over time. Equality based on ID.
java
@Entity
@Data
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@EqualsAndHashCode.Include
private Long id;
@Embedded
private Email email;
private String name;
@Builder.Default
private Instant createdAt = Instant.now();
}拥有持久化的唯一标识,基于ID判断相等性。
java
@Entity
@Data
@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@EqualsAndHashCode.Include
private Long id;
@Embedded
private Email email;
private String name;
@Builder.Default
private Instant createdAt = Instant.now();
}Value Object
Value Object(值对象)
Immutable, equality based on attributes.
java
@Embeddable
@Value
public class Email {
private String value;
private Email(String value) {
this.value = value;
}
public static Email of(String value) {
if (value == null || !value.contains("@")) {
throw new IllegalArgumentException("Invalid email");
}
return new Email(value);
}
// Lombok @Value makes it immutable and generates equals/hashCode
}具备不可变性,基于属性判断相等性。
java
@Embeddable
@Value
public class Email {
private String value;
private Email(String value) {
this.value = value;
}
public static Email of(String value) {
if (value == null || !value.contains("@")) {
throw new IllegalArgumentException("Invalid email");
}
return new Email(value);
}
// Lombok @Value makes it immutable and generates equals/hashCode
}Aggregate
Aggregate(聚合)
Cluster of entities and value objects with a root entity.
java
@Entity
@Data
public class Order { // Aggregate Root
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "order_id")
private List<OrderItem> items = new ArrayList<>();
private Long userId;
@Enumerated(EnumType.STRING)
private OrderStatus status;
// Business logic in domain model
public void addItem(Long productId, int quantity) {
// Business rules enforced here
if (this.status != OrderStatus.DRAFT) {
throw new IllegalStateException("Cannot add items to submitted order");
}
OrderItem item = OrderItem.builder()
.productId(productId)
.quantity(quantity)
.build();
this.items.add(item);
}
public Money getTotal() {
return items.stream()
.map(OrderItem::getSubtotal)
.reduce(Money.zero(), Money::add);
}
public void submit() {
if (items.isEmpty()) {
throw new IllegalStateException("Cannot submit empty order");
}
this.status = OrderStatus.SUBMITTED;
}
}由实体和值对象组成的集群,包含一个根实体(Aggregate Root)。
java
@Entity
@Data
public class Order { // Aggregate Root
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "order_id")
private List<OrderItem> items = new ArrayList<>();
private Long userId;
@Enumerated(EnumType.STRING)
private OrderStatus status;
// Business logic in domain model
public void addItem(Long productId, int quantity) {
// Business rules enforced here
if (this.status != OrderStatus.DRAFT) {
throw new IllegalStateException("Cannot add items to submitted order");
}
OrderItem item = OrderItem.builder()
.productId(productId)
.quantity(quantity)
.build();
this.items.add(item);
}
public Money getTotal() {
return items.stream()
.map(OrderItem::getSubtotal)
.reduce(Money.zero(), Money::add);
}
public void submit() {
if (items.isEmpty()) {
throw new IllegalStateException("Cannot submit empty order");
}
this.status = OrderStatus.SUBMITTED;
}
}Repository
Repository(仓库)
Abstracts data access for aggregates.
java
@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
Optional<Order> findById(Long id);
@Query("SELECT o FROM Order o LEFT JOIN FETCH o.items WHERE o.id = :id")
Optional<Order> findByIdWithItems(@Param("id") Long id);
List<Order> findByUserIdAndStatus(Long userId, OrderStatus status);
}对聚合根的数据访问逻辑进行抽象封装。
java
@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
Optional<Order> findById(Long id);
@Query("SELECT o FROM Order o LEFT JOIN FETCH o.items WHERE o.id = :id")
Optional<Order> findByIdWithItems(@Param("id") Long id);
List<Order> findByUserIdAndStatus(Long userId, OrderStatus status);
}Domain Event
Domain Event(领域事件)
Something that happened in the domain.
java
@Value
@Builder
public class OrderPlaced {
Long orderId;
Long userId;
Instant occurredAt;
}
// Publishing domain events with Spring
@Service
@Transactional
public class OrderService {
private final OrderRepository orderRepository;
private final ApplicationEventPublisher eventPublisher;
public void placeOrder(Long orderId) {
Order order = orderRepository.findById(orderId)
.orElseThrow(() -> new OrderNotFoundException(orderId));
order.submit();
orderRepository.save(order);
// Publish domain event
OrderPlaced event = OrderPlaced.builder()
.orderId(order.getId())
.userId(order.getUserId())
.occurredAt(Instant.now())
.build();
eventPublisher.publishEvent(event);
}
}
// Event listener
@Component
public class OrderEventHandler {
@EventListener
@Async
public void handleOrderPlaced(OrderPlaced event) {
// Send confirmation email, update inventory, etc.
}
}记录领域内发生的重要业务事件。
java
@Value
@Builder
public class OrderPlaced {
Long orderId;
Long userId;
Instant occurredAt;
}
// Publishing domain events with Spring
@Service
@Transactional
public class OrderService {
private final OrderRepository orderRepository;
private final ApplicationEventPublisher eventPublisher;
public void placeOrder(Long orderId) {
Order order = orderRepository.findById(orderId)
.orElseThrow(() -> new OrderNotFoundException(orderId));
order.submit();
orderRepository.save(order);
// Publish domain event
OrderPlaced event = OrderPlaced.builder()
.orderId(order.getId())
.userId(order.getUserId())
.occurredAt(Instant.now())
.build();
eventPublisher.publishEvent(event);
}
}
// Event listener
@Component
public class OrderEventHandler {
@EventListener
@Async
public void handleOrderPlaced(OrderPlaced event) {
// Send confirmation email, update inventory, etc.
}
}Strategic Patterns
战略模式
Anti-Corruption Layer
Anti-Corruption Layer(防腐层)
Translate between your model and external systems.
实现自身领域模型与外部系统之间的适配转换。
Shared Kernel
Shared Kernel(共享内核)
Shared subset of domain model between contexts.
不同限界上下文之间共享的领域模型子集。
Customer-Supplier
Customer-Supplier(客户-供应商)
Upstream provides what downstream needs.
上游系统按需提供下游系统所需的模型或服务。