Riguz留言 | 贡献
创建页面,内容为“= 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. **…”
 
Riguz留言 | 贡献
无编辑摘要
第4行: 第4行:


== Key Principles of DDD ==
== Key Principles of DDD ==
1. **Focus on the Domain**:
* '''Focus on the Domain''':
  - The domain model represents the core business logic and rules.
** The domain model represents the core business logic and rules.
  - It should be independent of technical concerns like persistence or frameworks.
** It should be independent of technical concerns like persistence or frameworks.


2. **Separation of Concerns**:
* '''Separation of Concerns''':
  - Divide responsibilities between the domain layer, application layer, and infrastructure layer.
** Divide responsibilities between the domain layer, application layer, and infrastructure layer.
  - Keep the domain layer free from infrastructure dependencies.
** Keep the domain layer free from infrastructure dependencies.


3. **Ubiquitous Language**:
* '''Ubiquitous Language''':
  - Use a shared language between developers and domain experts to ensure clarity and alignment.
** Use a shared language between developers and domain experts to ensure clarity and alignment.


4. **Repository Pattern**:
* '''Repository Pattern''':
  - Use repositories to abstract persistence logic and provide access to domain objects.
** Use repositories to abstract persistence logic and provide access to domain objects.


== Layers in DDD ==
== Layers in DDD ==
第22行: 第22行:
The domain layer contains the core business logic and domain models.
The domain layer contains the core business logic and domain models.


* **Responsibilities**:
* '''Responsibilities''':
  - Encapsulate business rules and behavior.
** Encapsulate business rules and behavior.
  - Represent the core concepts of the domain.
** Represent the core concepts of the domain.


* **Key Components**:
* '''Key Components''':
  - **Entities**: Objects with a unique identity (e.g., `Todo`).
** '''Entities''': Objects with a unique identity (e.g., `Todo`).
  - **Value Objects**: Immutable objects that represent a concept (e.g., `TodoId`).
** '''Value Objects''': Immutable objects that represent a concept (e.g., `TodoId`).
  - **Aggregates**: A cluster of domain objects treated as a single unit.
** '''Aggregates''': A cluster of domain objects treated as a single unit.


* **Best Practices**:
* '''Best Practices''':
  - Avoid adding persistence-related methods (e.g., `save()` or `delete()`) to domain models.
** Avoid adding persistence-related methods (e.g., `save()` or `delete()`) to domain models.
  - Keep domain models focused on business logic.
** Keep domain models focused on business logic.


* **Example**:
* '''Example''':
  <syntaxhighlight lang="java">
<syntaxhighlight lang="java">
  public class Todo {
public class Todo {
      private TodoId id;
    private TodoId id;
      private String title;
    private String title;
      private String description;
    private String description;
      private boolean completed;
    private boolean completed;


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


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


      // Getters and setters
    // Getters and setters
  }
}
  </syntaxhighlight>
</syntaxhighlight>


=== 2. Application Layer ===
=== 2. Application Layer ===
The application layer coordinates use cases and orchestrates interactions between the domain and infrastructure layers.
The application layer coordinates use cases and orchestrates interactions between the domain and infrastructure layers.


* **Responsibilities**:
* '''Responsibilities''':
  - Handle application-specific logic (e.g., workflows, use cases).
** Handle application-specific logic (e.g., workflows, use cases).
  - Delegate persistence to repositories.
** Delegate persistence to repositories.


* **Example**:
* '''Example''':
  <syntaxhighlight lang="java">
<syntaxhighlight lang="java">
  public class TodoApplicationService {
public class TodoApplicationService {
      private final TodoRepository todoRepository;
    private final TodoRepository todoRepository;


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


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


=== 3. Infrastructure Layer ===
=== 3. Infrastructure Layer ===
The infrastructure layer handles technical concerns like persistence, messaging, and external APIs.
The infrastructure layer handles technical concerns like persistence, messaging, and external APIs.


* **Responsibilities**:
* '''Responsibilities''':
  - Implement repository interfaces defined in the domain layer.
** Implement repository interfaces defined in the domain layer.
  - Map between domain models and database entities.
** Map between domain models and database entities.


* **Example**:
* '''Example''':
  <syntaxhighlight lang="java">
<syntaxhighlight lang="java">
  @Repository
@Repository
  public class JpaTodoRepository implements TodoRepository {
public class JpaTodoRepository implements TodoRepository {
      private final SpringDataTodoEntityRepository entityRepository;
    private final SpringDataTodoEntityRepository entityRepository;


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


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


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


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


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


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


* **Interface in the Domain Layer**:
* '''Interface in the Domain Layer''':
  - Define the contract for persistence using domain models.
** Define the contract for persistence using domain models.
  <syntaxhighlight lang="java">
<syntaxhighlight lang="java">
  public interface TodoRepository {
public interface TodoRepository {
      void save(Todo todo);
    void save(Todo todo);
      Optional<Todo> findById(TodoId id);
    Optional<Todo> findById(TodoId id);
      List<Todo> findAll();
    List<Todo> findAll();
  }
}
  </syntaxhighlight>
</syntaxhighlight>


* **Implementation in the Infrastructure Layer**:
* '''Implementation in the Infrastructure Layer''':
  - Implement the repository interface using database-specific entities and persistence mechanisms.
** Implement the repository interface using database-specific entities and persistence mechanisms.


== Mapping Between Domain Models and Database Entities ==
== 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.
To keep the domain layer independent of persistence, map between domain models and database entities in the infrastructure layer.


* **Domain Model**:
* '''Domain Model''':
  <syntaxhighlight lang="java">
<syntaxhighlight lang="java">
  public class Todo {
public class Todo {
      private TodoId id;
    private TodoId id;
      private String title;
    private String title;
      private String description;
    private String description;
      private boolean completed;
    private boolean completed;


      // Business logic
    // Business logic
  }
}
  </syntaxhighlight>
</syntaxhighlight>


* **Database Entity**:
* '''Database Entity''':
  <syntaxhighlight lang="java">
<syntaxhighlight lang="java">
  @Entity
@Entity
  @Table(name = "todos")
@Table(name = "todos")
  public class TodoEntity {
public class TodoEntity {
      @Id
    @Id
      @GeneratedValue(strategy = GenerationType.IDENTITY)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
      private Long id;
    private Long id;


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


      // Getters and setters
    // Getters and setters
  }
}
  </syntaxhighlight>
</syntaxhighlight>


== Best Practices ==
== Best Practices ==
1. Use **domain models** in the repository interface, not database entities.
* Use '''domain models''' in the repository interface, not database entities.
2. Keep the domain layer free from persistence concerns.
* Keep the domain layer free from persistence concerns.
3. Use mappers (manual or libraries like MapStruct) to convert between domain models and database entities.
* 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.
* 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.
* Use the '''Unit of Work''' or '''event-driven mechanisms''' for automatic persistence if needed.


== Summary ==
== Summary ==
- The domain layer focuses on business logic and uses repositories to abstract persistence.
* 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.
* 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.
* Keep the domain layer decoupled from technical concerns to ensure clean, maintainable, and testable code.


[[Category:DDD]]
[[Category:DDD]]
[[Category:MicroService]]
[[Category:MicroService]]

2025年7月30日 (三) 03:14的版本

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

  • 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.
  • Separation of Concerns:
    • Divide responsibilities between the domain layer, application layer, and infrastructure layer.
    • Keep the domain layer free from infrastructure dependencies.
  • Ubiquitous Language:
    • Use a shared language between developers and domain experts to ensure clarity and alignment.
  • 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

  • Use domain models in the repository interface, not database entities.
  • Keep the domain layer free from persistence concerns.
  • Use mappers (manual or libraries like MapStruct) to convert between domain models and database entities.
  • Avoid adding persistence-related methods (e.g., `save()`) to domain models.
  • 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.