728x90
- 상위 계층에서 하위 계층으로의 의존만 존재하고 하위 계층은 상위 계층에 의존하지 않는다.
1. 표현 영역 (Presentation Layer)
- 사용자 인터페이스(UI)를 담당
- 사용자와 직접 상호 작용하며, 시각적 요소와 기능을 제공
- 예시: JSP, Thymeleaf, React, Vue.js 등
2. 응용 영역 (Application Layer)
- 비즈니스 규칙을 구현
- 도메인 모델과 상호 작용하여 사용자 요청을 처리
- 예시: 서비스 클래스, 유틸리티 클래스 등
@Transactional
public void cancel(OrderNo orderNo, Canceller canceller) {
Order order = orderRepository.findById(orderNo)
.orElseThrow(() -> new NoOrderException());
if (!cancelPolicy.hasCancellationPermission(order, canceller)) {
throw new NoCancellablePermission();
}
order.cancel();
}
3. 도메인 영역 (Domain Layer)
- 도메인의 핵심 로직 구현
- 비즈니스 핵심 개념과 규칙을 담당
- 엔티티, 값 객체, 저장소 등을 포함
- 예시: 엔티티 클래스, 인터페이스, 저장소 인터페이스 등
@Entity
@Table(name = "purchase_order")
@Access(AccessType.FIELD)
public class Order {
@EmbeddedId
private OrderNo number;
@Version
private long version;
@Embedded
private Orderer orderer;
...
...
// 핵심 로직 구현
public void cancel() {
verifyNotYetShipped();
this.state = OrderState.CANCELED;
Events.raise(new OrderCanceledEvent(number.getNumber()));
}
4. 인프라스트럭처 영역 (Infrastructure Layer)
- 데이터베이스, 파일 시스템, 네트워킹 등 외부 시스템과의 상호 작용을 담당
- 도메인 모델에 영향을 주지 않고 외부 시스템에 대한 추상화 계층을 제공
- 예시: JDBC, JPA, Spring Data JPA 등
public interface UserRepository extends JpaRepository<User, Long> {}
- DIP (의존역전의 원칙)
- DIP 원칙은 고수준 모듈이 저수준 모듈의 구현에 직접 의존해서는 안 되며, 저수준 모듈이 고수준 모듈에서 정의한 추상 타입에 의존해야 한다는 개념
- 고수준 모듈: 추상화된 개념으로, 의미 있는 단일 기능을 제공합니다. 구체적인 구현보다는 기능의 정의에 집중
- 저수준 모듈: 구체적인 구현을 담당하며, 고수준 모듈에서 필요한 하위 기능을 제공
- 변경 효율성 향상: A사 알람 기능 API가 변경되어도 AlarmService 인터페이스를 만족하는 다른 구현체로 쉽게 교체 가능
- 테스트 용이성 향상: AlarmService 인터페이스를 구현하는 모의 객체를 사용하여 알람 서비스를 쉽게 테스트 가능
- 코드의 결합도 감소: 알람 기능에 대한 의존성을 추상화하여 코드의 결합도를 낮출 수 있음.
- DIP 원칙은 고수준 모듈이 저수준 모듈의 구현에 직접 의존해서는 안 되며, 저수준 모듈이 고수준 모듈에서 정의한 추상 타입에 의존해야 한다는 개념
// DIP 예제
// 알림 인터페이스 생성
public interface AlarmService {
void sendAlarm(String message);
}
// A사 알람 구현
public class AAlarmService implements AlarmService {
@Override
public void sendAlarm(String message) {
// A사 알람 기능 API 사용
System.out.println("A사 알람: " + message);
}
}
// B사 알람 구현
public class BAlarmService implements AlarmService {
@Override
public void sendAlarm(String message) {
// B사 알람 기능 API 사용
System.out.println("B사 알람: " + message);
}
}
public class Main {
public static void main(String[] args) {
AlarmService alarmService = new AAlarmService(); // A사 알람 기능 사용
alarmService.sendAlarm("알람 메시지");
alarmService = new BAlarmService(); // B사 알람 기능 사용
alarmService.sendAlarm("알람 메시지");
}
}
- 도메인 영역의 주요 구성요소
1. 엔티티
- 도메인의 독립적인 존재
- 고유한 식별자를 가지고 있음
- 상태와 행위를 가짐
- 예시: 고객, 주문, 제품
2. 밸류
- 엔티티의 속성을 나타내는 값 객체
- 불변하며, 동일성 비교를 통해 식별
- 예시: 이름, 주소, 전화번호
3. 애그리거트
- 엔티티들의 논리적 그룹
- 일관성을 유지하는 하나의 단위로 작동
- 부모 엔티티(루트 엔티티)와 자식 엔티티로 구성
- 예시
- 주문: 주문 엔티티, 주문 항목 엔티티, 배송 정보 밸류 객체
- 고객: 고객 엔티티, 주소 밸류 객체, 연락처 밸류 객체
4. 리포지터리
- 특정 엔티티 또는 애그리거트에 대한 데이터 접근을 담당
- CRUD(Create, Read, Update, Delete) 작업을 수행
- 도메인 로직과 분리되어 구현
- 예시: 고객 리포지터리, 주문 리포지터리
5. 도메인 서비스
- 복잡한 비즈니스 로직을 수행하는 객체
- 여러 엔티티 또는 애그리거트에 걸쳐 작동
- 재사용 가능한 독립적인 단위
- 예시: 주문 처리 서비스, 결제 서비스
- 도메인 모델 엔티티와 DB 테이블의 엔티티 구분
- 도메인 모델 엔티티 : 데이터 + 도메인 기능
public class Order { private Long id; private Customer customer; private List<OrderItem> orderItems; private OrderStatus orderStatus; // 밸류(값) 타입 포함 가능 public void calculateTotalPrice() { // ... } }
- DB 테이블의 엔티티 : 테이블 구조에 필요한 속성
public class OrderEntity { private Long id; private Long customerId; }
- 모듈 예시
- 한 패키지에 가능하면 10 ~ 15 개 미만으로 타입 개수를 유지하려고 한다고 한다. ( 최범균님 )
# 표현 계층
presentation/
├── controller/
│ └── UserController.java
└── view/
└── user/
├── index.html
└── detail.html
# 응용 계층
application/
├── service/
│ └── UserService.java
└── util/
└── ValidationUtil.java
# 도메인 계층 - 여러 하위 도메인으로 분리 가능
domain/
├── entity/
│ └── User.java
├── product/
│ ├── entity/
│ │ └── Product.java
│ └── service/
│ └── ProductService.java
├── order/
│ ├── entity/
│ │ └── Order.java
│ └── service/
│ └── OrderService.java
└── cart/
├── entity/
│ └── Cart.java
└── service/
└── CartService.java
# 인프라 스트럭쳐
infrastructure/
├── repository/
│ └── UserRepository.java
└── dao/
└── UserDaoImpl.java
728x90
'Books > 도메인 주도 개발 시작하기' 카테고리의 다른 글
Chapter6. 응용 서비스와 표현 영역 (0) | 2024.04.08 |
---|---|
Chapter5. 스프링 데이터 JPA를 이용한 조회 기능 (0) | 2024.04.08 |
Chapter4. 리포지터리와 모델 구현 (0) | 2024.04.08 |
Chapter3. 애그리거트 (0) | 2024.04.07 |
Chapter1. 도메인 모델 시작하기 (0) | 2024.04.05 |
댓글