레이어드 아키텍처

레이어드 아키텍처

MVC + Service 패턴 — 각 레이어의 책임 분리

레이어 구조

View (InputView / OutputView)
  ↕
Controller
  ↕
Service
  ↕
Domain (Entity / Value Object)
레이어 책임 하면 안 되는 것
View 사용자 입출력만 비즈니스 로직, 검증
Controller 흐름 제어, try-catch 도메인 로직 직접 처리
Service 비즈니스 로직 조합 UI 관련 코드
Domain 핵심 규칙, 불변식 외부 의존성

Controller 책임

흐름 제어 + 예외 처리 반복

public class CalculatorController {
    private final InputView inputView;
    private final OutputView outputView;
    private final CalculatorService service;

    public void run() {
        String input = readInput();
        int result = service.calculate(input);
        outputView.printResult(result);
    }

    private String readInput() {
        while (true) {
            try {
                return inputView.readExpression();
            } catch (IllegalArgumentException e) {
                outputView.printError(e.getMessage());
            }
        }
    }
}

Service 책임

여러 도메인 객체의 조합 — 트랜잭션 단위

public class RacingService {
    public RaceResult race(Cars cars, int attempts) {
        List<RoundResult> rounds = new ArrayList<>();
        for (int i = 0; i < attempts; i++) {
            cars.race();
            rounds.add(new RoundResult(cars.getPositions()));
        }
        return new RaceResult(rounds);
    }
}

Service가 하지 않는 것


문자열 계산기 설계 흐름

입력: "//;\n1;2;3"
  ↓
InputView.readExpression()      # raw string 반환
  ↓
Parser.parse(input)             # 구분자 추출 + 숫자 분리
  ↓  ["1", "2", "3"]
Validator.validate(numbers)     # 음수 체크
  ↓
CalculatorService.sum(numbers)  # 합계 계산
  ↓
OutputView.printResult(result)

파싱 순서 주의

// ❌ 잘못된 순서: 파싱 전 검증
validate(input);   // 구분자가 포함된 raw string을 검증 → 오류
parse(input);

// ✅ 올바른 순서: 파싱 후 검증
List<String> tokens = parse(input);
validate(tokens);  // 숫자만 남은 상태에서 음수 검증

예외 처리 전략

Controller 레벨 일괄 처리

// 입력 루프 + 예외 처리를 Controller에서
while (true) {
    try {
        String input = inputView.read();
        process(input);
        break;
    } catch (IllegalArgumentException e) {
        System.out.println(e.getMessage());
    }
}

예외를 잡는 위치


MVC에서 Service 도입 이유

// Before: Controller가 너무 많은 일
Controller → 입력 처리 + 비즈니스 로직 + 출력

// After: 관심사 분리
Controller → 흐름 제어
Service    → 비즈니스 로직
View       → 입출력

Service 도입 시 장점:

관련 개념