설명: DDD 원칙에 따르면 엔티티는 데이터를 담는 역할을 하고, 비즈니스 로직은 서비스 계층에 두는 것이 좋다고 합니다. 하지만 특정 상황에서는 엔티티에 비즈니스 로직을 포함하여 응집도를 높일 수 있습니다.
Java 예제:
public class Order {
private List<OrderItem> items;
public void verifyDuplicateOrderItemId(String itemId) {
boolean isDuplicate = items.stream().anyMatch(item -> item.getId().equals(itemId));
if (isDuplicate) {
throw new IllegalArgumentException("Duplicate item ID found");
}
}
public void orderCancel() {
// 주문 취소 로직
System.out.println("Order cancelled");
}
}
Python 예제:
class Order:
def __init__(self, items):
self.items = items
def verify_duplicate_order_item_id(self, item_id):
if any(item['id'] == item_id for item in self.items):
raise ValueError("Duplicate item ID found")
def order_cancel(self):
print("Order cancelled")
Reference: 도메인 모델 패턴과 트랜잭션 스크립트 패턴
public class OrderService {
public void processOrder(Order order) {
order.verifyDuplicateOrderItemId("123");
order.orderCancel();
}
}
class OrderService:
def process_order(self, order):
order.verify_duplicate_order_item_id("123")
order.order_cancel()
설명: 헥사고날 아키텍처는 도메인 로직과 외부 시스템의 의존성을 분리합니다. 하지만 ORM의 변경감지 기능을 사용할 수 없고 클래스 수가 많아져 복잡도가 증가할 수 있습니다.
Java 예제:
public interface PaymentRepository {
void save(Payment payment);
}
public class OrderService {
private final PaymentRepository paymentRepository;
public OrderService(PaymentRepository paymentRepository) {
this.paymentRepository = paymentRepository;
}
public void processPayment(Order order, Payment payment) {
paymentRepository.save(payment);
}
}
Python 예제:
class PaymentRepository:
def save(self, payment):
pass # DB 저장 로직
class OrderService:
def __init__(self, payment_repository):
self.payment_repository = payment_repository
def process_payment(self, order, payment):
self.payment_repository.save(payment)
Reference: 헥사고날 아키텍처와 의존성 역전
public class MessageProducer {
public void sendMessage(String message) {
System.out.println("Message sent: " + message);
}
}
class MessageProducer:
def send_message(self, message):
print(f"Message sent: {message}")
Reference: gRPC 및 메시지 브로커 사용 사례
설명: 엔티티와 DTO를 분리하면 데이터 전송과 비즈니스 로직을 명확히 구분할 수 있습니다. 공용 생성자는 불완전한 상태의 객체 생성을 초래할 수 있으므로 주의해야 합니다.
Java 예제:
public class Car {
private String status;
public Car(String status) {
if (status == null) {
throw new IllegalArgumentException("Status cannot be null");
}
this.status = status;
}
}
Python 예제:
class Car:
def __init__(self, status):
if status is None:
raise ValueError("Status cannot be null")
self.status = status
설명: 과거에는 AOP 사용 시 인터페이스 기반의 서비스 구현이 필수였으나, 현재는 클래스에 적용할 수 있는 프록시 패턴으로 인터페이스 사용이 꼭 필요하지는 않습니다.
Java 예제 (AOP와 인터페이스):
public interface OrderService {
void placeOrder(Order order);
}
public class OrderServiceImpl implements OrderService {
@Override
public void placeOrder(Order order) {
System.out.println("Order placed");
}
}
Reference: AOP와 인터페이스 기반 구현