객체 지향이라고 하면 꼭 나오는 단어가 있다.
그것은 바로 SOLID다.
좋은 객체 지향 설계의 5가지 원칙으로 꼭 나오는 SOLID는 과연 뭘까?
클린코드로 유명한 로버트 마틴이 좋은 객체 지향 설계의 5가지 원칙을 정리했다.
여기서 제일 중요한건 OCP와 DIP다.
class MemberService{
MemberRepository memberRepository = new MemoryMemberRepository();
}
여기서 MemoryMemberRepository의 구현체가 JdbcMemberRepository로 바뀔 때,
class MemberService{
MemberRepository memberRepository = new JdbcMemberRepository();
}
이 것은 OCP 원칙을 깨트리는 거다.
왜냐면 MemoryMemberRepository에서 JdbcMemberRepository라고 코드를 변경해야 하기 때문이다.
OCP 원칙을 지키기 위해서는 구현체를 이 코드에서 작성하지 않도록 하면 된다.
앞에서 OCP에서 나왔던 코드를 가져오면,
class MemberService{
MemberRepository memberRepository = new MemoryMemberRepository();
}
이 코드는 MemberRepository라는 인터페이스를 의존하지만 더불어 MemoryMemberRepository라는 구현클래스도 의존하고 있다.
따라서 DIP에 위반된다.
OCP와 DIP 모두 다형성만으로는 지킬 수 없다. AppConfig와 같은 코드를 써서 이 문제를 해결해줄 수 있다.
@Configuration
public class AppConfig {
@Bean
public MemberService memberService() {
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository() {
return new MemoryMemberRepository();
}
}
이렇게 하면 Appconfig에서만 레포지토리를 바꿔주면 된다.
스프링에서는 DI(의존성 주입)이 이걸 간단하게 해준다.
현재는 대부분의 경우 @Component 계열 애노테이션을 통해 스프링 DI가 자동으로 필요한 빈을 생성하고 주입하도록 할 수 있다. 예를 들어 @Service, @Repository, @Controller 애노테이션을 클래스에 붙이고, @Autowired 또는 생성자 주입을 통해 해당 빈을 주입받을 수 있다.
@Service
public class MemberService {
private final MemberRepository memberRepository;
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
}
위 코드에서 MemberService 클래스에 MemberRepository 생성자 주입 방식으로 주입하고 있다. 만약 MemberRepository 인터페이스의 구현 클래스(MemoryMemberRepository 등)가 @Repository로 등록되어 있다면, 스프링이 자동으로 이를 찾아 MemberService 생성자에 주입해준다.