[스프링 기초]스프링의 본질, 객체 지향 설계

LTEN·2022년 7월 22일
0

스프링 기초

목록 보기
2/6

※본 글은 김영한님의 '자바 스프링 완전정복 시리즈' 강의를 바탕으로 작성한 글입니다.

스프링을 단순히 웹 프로그래밍을 도와주는 프레임워크라고 생각할 수도 있지만, 그 본질은 객체 지향 프로그래밍에 있습니다.

앞서 좋은 객체 지향 설계를 위한 5가지 원칙, SOLID를 살펴보았습니다.
객체 지향 설계의 5가지 원칙(SOLID)

OCP, DIP 문제

이때 단순히 다형성만을 이용해서는 OCP, DIP를 완전히 만족할 수 없다는 내용을 다뤘었습니다.

interface MemberRepository{
    public void save(Member meber);
}
class MemoryMemberRepository implements Repository{
    public void save(Member member){
        // 메모리에 저장
    }
}
class DBRepository implements  Repository{
    public void save(Member member){
        // DB에 저장
    }
}

MemberRepository의 구현체가 위와 같이 존재할 때,

class MemberService{
    // MemberRepository memberRepository = new MemoryMemberRepository();
    // 구현체만 갈아끼우기
    MemberRepository memberRepository = new DBMemberRepository();
    
    void save(Member member){
        repository.save(member);
    }
}

MemberService에서 의존하는 구현체를 바꾸는 것만으로 Service가 Memory가 아닌 DB에 저장하도록 변경할 수 있었습니다.

다만 문제는 구현체를 갈아끼우는 것이 클라이언트 클래스의 코드의 수정을 통해 이뤄지기 때문에 완전히 OCP를 만족하지 못한다는 것이였습니다.
추가로 현재 구체 class에 의존하기 때문에 DIP도 만족하지 않습니다.

이 문제를 스프링 프레임워크를 통해 해결할 수 있습니다.

스프링을 통한 해결

먼저 스프링을 이용한 코드를 보겠습니다.

class MemberService{
	MemberRepository memberRepository;
    
    @Autowired
    public MemberService(MemberRepository memberRepository){
    	this.memberRepository = memberRepository;
    }
    
    void save(Member member){
        repository.save(member);
    }
}

스프링을 이용한 MemberSerivce 클래스의 코드는 위와 같습니다.
생성자를 통해 memberRepository를 초기화하고, 생성자에 @Autowired 어노테이션이 추가되어 있습니다.

어디에도 memberRepository의 구현체를 선택하는 코드는 없습니다.

@Autowired 어노테이션을 이용하면, 스프링 프레임워크가 스프링 컨테이너에 등록된 빈 중, 타입에 맞는 빈을 찾아서 꽂아주게 됩니다.
(물론 MemberService의 빈을 스프링을 통해 생성하는 경우입니다. JAVA 코드만으로 객체를 생성했을 때는 해당되지 않습니다.)

그렇다면 우리가 할 일은 스프링 컨테이너에 사용할 빈을 등록하는 것 뿐입니다.
다시 메모리에 저장하도록 MemoryMemberRepository를 사용하는 경우를 가정해보면,

interface MemberRepository{
    public void save(Member meber);
}

@Repository // 스프링 컨테이너에 빈 등록
class MemoryMemberRepository implements Repository{
    public void save(Member member){
        // 메모리에 저장
    }
}
class DBRepository implements  Repository{
    public void save(Member member){
        // DB에 저장
    }
}

위와 같이 사용할 구현체 위에 @Repository 어노테이션을 추가하면 됩니다.

이렇게 하면,
1. 스프링 컨테이너에 MemoryMemberRepository가 등록
2. @Autowired는 컨테이너에서 MemberRepository에 적합한 빈인 MemoryMemberRepository를 MemberService의 생성자에 전달
의 순서로 진행됩니다.

다시 DB를 이용하도록 바꿔주려면, @Repository의 위치만 변경해주면 됩니다.
즉, 클라이언트의 코드를 수정할 필요가 전혀 없어졌습니다.

단순한 예시이지만, 스프링 프레임워크의 본질은 위와 같이 좋은 객체 지향 설계를 도와준다는 것에 있습니다.

profile
백엔드

0개의 댓글