레이어드 아키텍처
레이어드 아키텍처
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가 하지 않는 것
- 입력 파싱 → View/Parser 담당
- 우승자 판별 로직 → Domain 담당 (Cars.getWinners())
문자열 계산기 설계 흐름
입력: "//;\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());
}
}
예외를 잡는 위치
- Domain: 예외 생성 및 throw
- Controller: 예외 catch + 재입력 유도
- Service: 일반적으로 예외를 직접 catch하지 않음
MVC에서 Service 도입 이유
// Before: Controller가 너무 많은 일
Controller → 입력 처리 + 비즈니스 로직 + 출력
// After: 관심사 분리
Controller → 흐름 제어
Service → 비즈니스 로직
View → 입출력
Service 도입 시 장점:
- Controller 단순화
- Service 단독 테스트 가능
- 동일 Service를 다른 Controller에서 재사용 가능
관련 개념
- 객체지향 설계 실전 - 도메인 레이어 설계
- 소프트웨어 설계 - 결합도 최소화