PHpullh

JAVA · 디자인패턴

CQRS 패턴

명령(Command)과 조회(Query)의 책임을 분리하는 CQRS 패턴입니다.

디자인패턴고급CQRSCommandQuery읽기쓰기분리

핵심 설명

명령(Command)과 조회(Query)의 책임을 분리하는 CQRS 패턴입니다.

Java code

import java.util.*;

// Command 모델 (쓰기)
interface Command {}
record CreateProductCommand(String name, int price) implements Command {}
record UpdatePriceCommand(String id, int newPrice) implements Command {}

// Query 모델 (읽기)
interface Query {}
record GetProductQuery(String id) implements Query {}
record SearchProductQuery(String keyword) implements Query {}

// 쓰기 모델
class ProductCommandHandler {
    private final Map<String, int[]> writeStore = new HashMap<>();

    String handle(CreateProductCommand cmd) {
        String id = UUID.randomUUID().toString().substring(0, 8);
        writeStore.put(id, new int[]{cmd.price()});
        System.out.println("생성: " + id);
        return id;
    }

    void handle(UpdatePriceCommand cmd) {
        writeStore.get(cmd.id())[0] = cmd.newPrice();
        System.out.println("가격 변경: " + cmd.id());
    }
}

// 읽기 모델 (비정규화된 뷰)
record ProductView(String id, String name, int price) {}

class ProductQueryHandler {
    private final Map<String, ProductView> readStore = new HashMap<>();

    void sync(String id, String name, int price) {
        readStore.put(id, new ProductView(id, name, price));
    }

    ProductView handle(GetProductQuery query) {
        return readStore.get(query.id());
    }

    List<ProductView> handle(SearchProductQuery query) {
        return readStore.values().stream()
            .filter(p -> p.name().contains(query.keyword()))
            .toList();
    }
}

학습 팁

CQRS를 사용하면 읽기 모델을 조회 패턴에 최적화(비정규화)할 수 있습니다. 이벤트 소싱과 함께 사용하면 시너지가 큽니다.

주의할 점

모든 시스템에 CQRS가 필요한 것은 아닙니다. 읽기/쓰기 패턴이 크게 다를 때만 도입하세요. 복잡성이 증가합니다.

자주 묻는 질문

CQRS 패턴란 무엇인가요?

명령(Command)과 조회(Query)의 책임을 분리하는 CQRS 패턴입니다.

CQRS 패턴 학습 시 주의할 점은 무엇인가요?

모든 시스템에 CQRS가 필요한 것은 아닙니다. 읽기/쓰기 패턴이 크게 다를 때만 도입하세요. 복잡성이 증가합니다.

Continue Learning

Java 학습을 이어가세요

총 200개의 독립 HTML 학습 문서 중 하나입니다. 각 문서는 고유 URL과 canonical 메타데이터를 가집니다.