본문 바로가기
BackEnd/스프링 핵심 원리

[스프링 핵심원리 이해] - 객체 지향 원리 -DIP, OCP (1)

by telecaster0 2024. 1. 24.

 

3년차로 현업에 있으면서 스프링의 원리와 기초가 부족한것 같아 강의를 듣기 시작했다.

 

그렇게 생각한 이유는

1. 흔히들 작성하는 코드 방식대로 따라서 기능은 구현했지만 왜 이렇게 사용하는지에 대한 이해가 수반되지 않았고

 

2. 스프링이라는것은 자바 프레임워크로써 자바를 좀더 효율적으로 사용할수있도록 도와주는 하나의 프레임워크라고 생각되는데

자바/스프링 개발자라고 내세우면서 기본적인 원리와 핵심이론 알아야 된다고 생각해 학습을 시작했다.

 

 

첫번째 수업은 바로 객체 지향 원리 적용이다.

 

쇼핑몰에서 회원등급별로 물건구매시 혜택이 주어지는 예제이며 크게 MemberService, OrderService로 나뉜다.

 

오늘은 일단 MemberService에 관해 작성해 보려고 한다.

 

MemberService는 크게 두가지 기능을 한다. 회원가입, 회원정보검색

 

그리고 회원정보검색은 두가지 방식을 경우에 따라 갈아끼울수있도록 작성할 것이다 

 

첫번째 방식은 코드의 메모리를 통해 불러오는 방식

두번째 방식은 DB에 접근하여 불러오는 방식

이 두가지 방식을 사용하게 될것이다.

 

다만 이 두가지 방식중 어떤 방식을 사용하더라도 회원가입(save), 회원정보검색(findByMemberId)을 사용하여야 하기 때문에 아래와 같이 추상(인터페이스) MemberRepository를 통해 기능들을 선언해 주었다.

 

interface MemberRepository{

	Member save(Long memberId,String username, Grade grade)
	Member findByMemberId(Long memberId);
}

////////
public class MemoryMemberRepository implements MemberRepository{

	private static Map<Long,Member> store = new HashMap<>();

	@Override
	public void save(Member member){
    	store.put(member.getId(),member);
        }
        
    @Override
	public Member findByMemberId(Long memberId){
    	return store.get(memberId);
    }
	
}
public interface MemberService{
	void join(Member member);
    Member findMember(Long memberId);	
}

/////
public class MemberServiceImpl implements MemberService{
	//(1)
	private MemberRepository repository= new MemoryMemberRepository();
	//(2)
    private MemberRepository repository = new DBMemberRepositroy();
    
    @Override
    public void join(Member member){
    	respository.save(member);
    }
    
    @Override
    public Member findMember(Long memberId){
    	return repository.findById(memberId);
    }

}

 

이 코드들은 모두 실행에 문제가 없다. 다만 객체지향의 지향방향인 SOLID원칙중 2가지 원칙에 어긋나게된다.

 

첫째,

MemberSerivceImplMemberRepository 인터페이스에 의존성을 가진다. 

그런데 문제는 구현체인 MemoryMemberRepostiory에도 의존성을 가지게 되는데

이는 SOLID원칙중 DIP(Dependency Inversion Principle) 의존관계 역전원칙에 어긋나게 된다.

인터페이스(추상화)에만 의존해야하는데 추상화와 구체화(MemoryMemberRepository에도 의존하고 있어 DIP에 어긋나게 되는것이다.

 

둘째,

메모리의 MemberRepository가 아닌 같은 기능을 하지만 DB방식의 MemberRepository의 기능을 수행하려면 (2)처럼 구현해야하고 (1)을 주석처리 해야 한다.

이 방법 또한 앞서 말한 것처럼 DIP의 원칙에도 어긋나고

OCP(Open/Closed Principle) 개방-폐쇄 원칙에도 어긋나게 된다.

'확장에는 열려있고 변경에는 닫혀있어야한다.'는 원칙이지만

위의 방식으로 사용하게 되면 코드를 주석처리나 삭제해야하는 코드변경이 일어나야 하기때문에 OCP의 원칙에 어긋나게 되는것이다.

그리고 이 원칙들을 지켜 객체지향설계에 맞게 코드를 바꿔보려 한다.