객체지향 설계와 스프링

고동현·2024년 3월 15일
0

Spring 기본

목록 보기
1/10

이번 시간부터는 스프링 기본편이 되겠다.
스프링에서 제일 중요한게 뭐냐 하면 다형성을 꼽을 수 있겠다.
이전 입문편에서 DI,Ioc등을 맛보았다면,
입문편에서 배운것들을 자세히 배워보고, 스프링 mvc 프레임워크가 어떤식으로 로직이 구현되어있는지 살펴볼 것이다.

다형성

다형성을 실세계로 비유를 해보자면
역할과 구현으로 세상을 구분하는것이다.
예를들어, 자동차 면허증이 있다고 치자, 그러면 자동차 면허증만 있다면, k3,아반떼,소나타등 어떠한 차량(구현체)가 와도 운전이 가능하다.
k3운전 면허증, 아반떼 운전면허증, 소나타 운전면허증이 따로있는것이 아니기 때문이다.
다른예시로, 로미오와 줄리엣 공연에 대해서 생각해보자.
로미오라는 역할을 정해두면, 구현으로 송혜교가 오던, 김태희가 오던 상관없이 로미오 역할을 수행할 수 있다.

이것처럼 역할과 구현으로 구분하면, 유연해지고 또 변경에 유리하다.
장점

  • 클라이언트는 인터페이스만 알면된다.
  • 클라이언트는 구현대상의 내부 구조를 몰라도된다.
  • 클라이언트는 구현 대상의 내부 구조가 변경되어도 영향을 받지 않는다.

생각해보면, 입문편에서 memberRepository에서 save라는 함수를 클라이언트가 알기만 했지 실제 구현되어있는 MemoryMemberRepository나 JPAMemberREpository의 save메서드가 어떤식으로 구현되어있는지 전혀 알 필요가 없었다.

자바의 다형성을 생각해보자
Overriding
다형성을 통해 인터페이스를 구현한 객체를 실행시점에 유연하게 변경할 수 있다.

클라이언트인 MemberService는 서버에있는 Memory의 save,jdbc의 save 둘다 받을수 있다.
고로 save라는 기능만 클라이언트가 알고 있으면 되지
구현이 어떻게 되었고, 그 기능이 어떻게 되어있는지 전혀 몰라도 된다.

다형성의 본질
인터페이스를 구현한 객체 인스턴스를 실행 시점에 유연하게 변경할 수 있다.
클라이언트를 변경하지 않고, 서버의 구현기능을 유연하게 변경 할 수있다.
MemberServiceForMemory memberService1 = new MemoryMemberRepository();

MemberServiceForJdbc memberService2 = new JdbcMemberRepository();

이런식으로 클라이언트를 여러개 안 만들고

내가 원하는데로 바꿔끼울 수 있다.

스프링에서 IoC제어의 역전과 DI는 다형성을 활용해서 역할과 구현을 더 편리하게 다루는것이다.
IoC,DI는 뭐 앞에서도 여러번 말씀드렸지만, 이번 기본편에서도 주구 장창 말할테니 걱정하지 마십쇼!!

좋은 객체 지향 설계의 5가지 원칙-SOLID

SOLID-좋은 객체 지향 설계의 5가지 원칙

  • SRP:단일책임원칙
  • OCP:개방-폐쇄원칙
  • LSP:리스코프 치환 원칙
  • ISP:인터페이스 분리 원칙
  • DIP:의존관계 역전 원칙

SRP
변경이 있을때 파급이 적으면 적을수록 잘 설계한것이다.
한클래스는 하나의 책임만 가지는것.

OCP
소프트웨어 요소는 확장에는 열려 있으나 변경에는 닫혀있어야한다.
근데 생각해보면, 확장을 하려면 당연히 기존 코드를 변경해야하지않나?
=>다형성을 활용
인터페이스를 구현한 새로운 클래스를 하나 만들어서 새로운 기능을 구현

이런식으로 새로운 jdbcMemberRepsoitory라는 클래스를 만들어서 확장하였다.

근데 문제가있다.

뭐냐면, MemberService가 직접 구현 클래스를 선택한다.
즉, 확장을 위해서 새로운 클래스를 만들고 나서 보니까, 또 어차피 이 새로운 구현 클래스를 사용하기위해서 클라이언트(MemberService)코드를 고쳐야 하는것이다.

다형성을 사용했지만 OCP원칙을 지키지 못한것이다.

이것을 해결하기위해 조립,설정자가 필요하고 spring container가 해준다.

LSP
다형성에서 하위 클래스는 인터페이스 규약을 다 지켜야한다는것,
예를들어 자동차 엑셀은 앞으로가라는 기능이다. 만약 내가 내맘대로, 뒤로가게 구현하면 실행은 되겠지만 LSP를 위반하게 된 것이다.

ISP
특정 클라이언트를 위한 인터페이스 여러개가 범용 인터페이스 하나보다 낫다.
자동차 인터페이스=>운전 인터페이스, 정비 인터페이스로 분리
사용자 클라이언트=>운전자 클라이언트,정비사 클라이언트로 분리
이렇게되면, 정비 인터페이스가 변경되어도 운전자 클라이언트에 영향을 주지 않음

DIP
구현 클래스에 의존하지 말고, 인터페이스에 의존해라.
이말을 들으면, 어? 이게 어떻게 가능하지 싶을 수 있다.
왜냐하면 위에서 사진을 보면, MemberRepository라는 인터페이스에는 잘 의존을 하고있는데 결국 구현체인 jdbc이던 memory이던 의존을 하고 있기 때문이다.
그런데 곰곰히 생각을 해보면, 아니 구현체가 없는데 인터페이스만 가지고 어떻게 구현을 하냐? 싶을 수 있다.
말그대로 MemberService memberService; 딱 이렇게 끝나는건데
즉, 다형성 만으로는 OCP와 DIP를 지킬 수 없다.=>갈아끼우기가 불가능하다는말임

그래서,스프링은 DI를 통해서 OCP,DIP를 가능하게 지원한다.
이를 통해, 클라이언트 코드의 변경없이 기능 확장=>memberService부분을 고지치 않고 기능 확장 가능

profile
항상 Why?[왜썻는지] What?[이를 통해 무엇을 얻었는지 생각하겠습니다.]

0개의 댓글