DDD guide

Riguz留言 | 贡献2025年7月30日 (三) 03:11的版本 (创建页面,内容为“= Domain-Driven Design (DDD) Guide = This guide provides an overview of key concepts and best practices for implementing Domain-Driven Design (DDD), focusing on the separation of concerns between the domain model, repository, and persistence layer. == Key Principles of DDD == 1. **Focus on the Domain**: - The domain model represents the core business logic and rules. - It should be independent of technical concerns like persistence or frameworks. 2. **…”)
(差异) ←上一版本 | 最后版本 (差异) | 下一版本→ (差异)

Domain-Driven Design (DDD) Guide

This guide provides an overview of key concepts and best practices for implementing Domain-Driven Design (DDD), focusing on the separation of concerns between the domain model, repository, and persistence layer.

Key Principles of DDD

1. **Focus on the Domain**:

  - The domain model represents the core business logic and rules.
  - It should be independent of technical concerns like persistence or frameworks.

2. **Separation of Concerns**:

  - Divide responsibilities between the domain layer, application layer, and infrastructure layer.
  - Keep the domain layer free from infrastructure dependencies.

3. **Ubiquitous Language**:

  - Use a shared language between developers and domain experts to ensure clarity and alignment.

4. **Repository Pattern**:

  - Use repositories to abstract persistence logic and provide access to domain objects.

Layers in DDD

1. Domain Layer

The domain layer contains the core business logic and domain models.

  • **Responsibilities**:
 - Encapsulate business rules and behavior.
 - Represent the core concepts of the domain.
  • **Key Components**:
 - **Entities**: Objects with a unique identity (e.g., `Todo`).
 - **Value Objects**: Immutable objects that represent a concept (e.g., `TodoId`).
 - **Aggregates**: A cluster of domain objects treated as a single unit.
  • **Best Practices**:
 - Avoid adding persistence-related methods (e.g., `save()` or `delete()`) to domain models.
 - Keep domain models focused on business logic.
  • **Example**:
  public class Todo {
      private TodoId id;
      private String title;
      private String description;
      private boolean completed;

      public Todo(TodoId id, String title, String description) {
          this.id = id;
          this.title = title;
          this.description = description;
          this.completed = false;
      }

      public void markAsCompleted() {
          this.completed = true;
      }

      // Getters and setters
  }

2. Application Layer

The application layer coordinates use cases and orchestrates interactions between the domain and infrastructure layers.

  • **Responsibilities**:
 - Handle application-specific logic (e.g., workflows, use cases).
 - Delegate persistence to repositories.
  • **Example**:
  public class TodoApplicationService {
      private final TodoRepository todoRepository;

      public TodoApplicationService(TodoRepository todoRepository) {
          this.todoRepository = todoRepository;
      }

      public void createTodo(String title, String description) {
          Todo todo = new Todo(new TodoId(UUID.randomUUID()), title, description);
          todoRepository.save(todo);
      }
  }

3. Infrastructure Layer

The infrastructure layer handles technical concerns like persistence, messaging, and external APIs.

  • **Responsibilities**:
 - Implement repository interfaces defined in the domain layer.
 - Map between domain models and database entities.
  • **Example**:
  @Repository
  public class JpaTodoRepository implements TodoRepository {
      private final SpringDataTodoEntityRepository entityRepository;

      public JpaTodoRepository(SpringDataTodoEntityRepository entityRepository) {
          this.entityRepository = entityRepository;
      }

      @Override
      public void save(Todo todo) {
          TodoEntity entity = mapToEntity(todo);
          entityRepository.save(entity);
      }

      @Override
      public Optional<Todo> findById(TodoId id) {
          return entityRepository.findById(id.getValue())
                                 .map(this::mapToDomain);
      }

      private TodoEntity mapToEntity(Todo todo) {
          TodoEntity entity = new TodoEntity();
          entity.setId(todo.getId().getValue());
          entity.setTitle(todo.getTitle());
          entity.setDescription(todo.getDescription());
          entity.setCompleted(todo.isCompleted());
          return entity;
      }

      private Todo mapToDomain(TodoEntity entity) {
          return new Todo(
              new TodoId(entity.getId()),
              entity.getTitle(),
              entity.getDescription(),
              entity.isCompleted()
          );
      }
  }

Repository Pattern

The repository pattern abstracts persistence logic and provides access to domain objects.

  • **Interface in the Domain Layer**:
 - Define the contract for persistence using domain models.
  public interface TodoRepository {
      void save(Todo todo);
      Optional<Todo> findById(TodoId id);
      List<Todo> findAll();
  }
  • **Implementation in the Infrastructure Layer**:
 - Implement the repository interface using database-specific entities and persistence mechanisms.

Mapping Between Domain Models and Database Entities

To keep the domain layer independent of persistence, map between domain models and database entities in the infrastructure layer.

  • **Domain Model**:
  public class Todo {
      private TodoId id;
      private String title;
      private String description;
      private boolean completed;

      // Business logic
  }
  • **Database Entity**:
  @Entity
  @Table(name = "todos")
  public class TodoEntity {
      @Id
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      private Long id;

      private String title;
      private String description;
      private boolean completed;

      // Getters and setters
  }

Best Practices

1. Use **domain models** in the repository interface, not database entities. 2. Keep the domain layer free from persistence concerns. 3. Use mappers (manual or libraries like MapStruct) to convert between domain models and database entities. 4. Avoid adding persistence-related methods (e.g., `save()`) to domain models. 5. Use the **Unit of Work** or **event-driven mechanisms** for automatic persistence if needed.

Summary

- The domain layer focuses on business logic and uses repositories to abstract persistence. - The infrastructure layer handles persistence and maps between domain models and database entities. - Keep the domain layer decoupled from technical concerns to ensure clean, maintainable, and testable code.