BoardConfig 객체 조립
객체 생성과 구현 선택을 구성 루트에 모아 회원가입·로그인 서비스가 공유하는 객체 그래프를 한곳에서 읽습니다.
생성자 주입을 적용하면 서비스는 구현을 선택하지 않습니다.
프로그램 시작 지점에서 객체를 만들고 연결하는 코드를 한곳에 모읍니다.
BoardConfig는 업무를 수행하지 않고 객체 그래프만 만듭니다.
BoardConfig만 보면 애플리케이션에서 실제로 쓰는 구현을 한눈에 확인할 수 있다.
- Adapters
repository·hasher 생성
- Service
역할을 생성자로 연결
- Entrypoint
controller에 service 전달
- Lifecycle
공유 객체와 종료 책임
구성 루트
package board;
import board.member.*;
public final class BoardConfig {
private final MemberRepository members =
new MemoryMemberRepository();
private final PasswordHasher passwordHasher =
new TestPasswordHasher();
public MemberRegistrationService memberRegistrationService() {
return new DefaultMemberRegistrationService(
members, passwordHasher);
}
public LoginService loginService() {
return new LoginService(members, passwordHasher);
}
}회원가입과 로그인은 같은 회원 저장소와 해시 구현을 사용합니다.
두 서비스가 서로를 직접 생성하지 않고 구성 루트가 각각 완성된 객체를 제공합니다.
실행 코드
public final class BoardApplication {
public static void main(String[] args) {
var config = new BoardConfig();
var registration = config.memberRegistrationService();
var login = config.loginService();
Member member = registration.register(new SignUpCommand(
"member@example.com", "안동민", "secret-1234"));
long loginMemberId = login.authenticate(
"member@example.com", "secret-1234");
System.out.println("registered=" + member.id());
System.out.println("login=" + loginMemberId);
}
}main은 Map 저장 방식이나 해시 문자열 형식을 모릅니다.
실행 진입점은 완성된 사용 사례를 호출할 뿐입니다.
구성 단계가 끝난 뒤에는 서비스가 null이나 미완성 의존성을 만날 이유가 없어야 한다.
- 1MemoryMemberRepository 생성
공유 저장소 인스턴스
- 2TestPasswordHasher 생성
첫 운영 정책
- 3DefaultMemberRegistrationService 생성
두 역할을 생성자로 연결
- 4register 호출
완성된 객체 그래프 사용
객체 생성과 업무 실행 구분
| 객체 | 책임 | 바뀌는 이유 |
|---|---|---|
DefaultMemberRegistrationService | 중복 확인·해시·저장 순서 | 회원가입 규칙 변경 |
MemoryMemberRepository | 메모리에 회원 저장 | 저장 기술 변경 |
PasswordHasher 구현 | 비밀번호 해시·비교 | 보안 정책 변경 |
BoardConfig | 구현 선택과 연결 | 실행 환경 변경 |
이 표의 변경 이유가 섞이면 다시 경계를 검토합니다.
변경 이유가 다른 코드를 한 클래스에 두지 않으면 테스트와 교체 범위가 작아진다.
| 영역 | 결정 | 변경 이유 |
|---|---|---|
| 구성 | 어떤 구현을 연결할지 | 환경·정책 변경 |
| 사용 | 회원가입 순서와 규칙 | 업무 요구 변경 |
| 인프라 | 어떻게 저장할지 | DB·캐시 변경 |
테스트 구성
테스트는 BoardConfig를 통하지 않고 필요한 가짜를 직접 전달할 수 있습니다.
반대로 실제 실행 그래프가 올바른지는 구성 테스트 한 곳에서 확인합니다.
@Test
void 회원가입과_로그인은_같은_회원_저장소를_사용한다() {
var config = new BoardConfig();
config.memberRegistrationService().register(new SignUpCommand(
"member@example.com", "회원", "secret-1234"));
assertThat(config.loginService().authenticate(
"member@example.com", "secret-1234")).isPositive();
}등록과 조회가 서로 다른 저장소 인스턴스를 받으면 타입은 같아도 객체 그래프는 끊어진다.
- Registration
회원 저장
- Query
같은 상태 조회
- Identity
동일 instance 전달
- Boundary
구성 루트가 공유 범위 결정
다음 문서에서는 구성 메서드가 매번 새 저장소를 만들 때 발생하는 공유 실패와 객체 수명을 다룹니다.