2장 : 객체지향 설계와 Spring
BoardConfig 객체 조립
객체 생성과 구현 선택을 구성 루트에 모아 회원가입·로그인 서비스가 공유하는 객체 그래프를 한곳에서 읽습니다.
생성자 주입을 적용하면 서비스는 구현을 선택하지 않습니다.
프로그램 시작 지점에서 객체를 만들고 연결하는 코드를 한곳에 모읍니다.
BoardConfig는 업무를 수행하지 않고 객체 그래프만 만듭니다.
구성 루트
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 저장 방식이나 해시 문자열 형식을 모릅니다.
실행 진입점은 완성된 사용 사례를 호출할 뿐입니다.
객체 생성과 업무 실행 구분
| 객체 | 책임 | 바뀌는 이유 |
|---|---|---|
DefaultMemberRegistrationService | 중복 확인·해시·저장 순서 | 회원가입 규칙 변경 |
MemoryMemberRepository | 메모리에 회원 저장 | 저장 기술 변경 |
PasswordHasher 구현 | 비밀번호 해시·비교 | 보안 정책 변경 |
BoardConfig | 구현 선택과 연결 | 실행 환경 변경 |
이 표의 변경 이유가 섞이면 다시 경계를 검토합니다.
테스트 구성
테스트는 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();
}다음 문서에서는 구성 메서드가 매번 새 저장소를 만들 때 발생하는 공유 실패와 객체 수명을 다룹니다.