본문 바로가기

스프링/기본편

객체 지향 설계와 스프링

728x90

스프링이란


스프링 프레임워크

 

스프링 부트

 

스프링의 핵심

 

좋은 객체 지향 프로그래밍


객체 지향 프로그래밍은 프로그램을 유연하고 변경이 용이하게 만들며 이를 다형성이라고 한다.

 

다형성을 비유하자면 역할과 구현으로 세상을 나눌 수 있다.

 

 운전자와 자동차를 비유로 들어보면 운전자 역할과 자동차 역할이 있다. 여기서 자동차는 변경되어도 운전자가 운전하는 것에 문제는 전혀 없다. 자동차 역할에 다른 자동차가 들어간다고 해도 운전을 못하게 되는 것이 아니라는 것이다. 이 이유는 자동차 역할에 대한 인터페이스에 따라서 자동차를 구현했기 때문이다. 

 운전자는 자동차의 자세한 내부를 몰라도 운전이 가능하다는 말은 새로운 자동차가 나와도 클라이언트가 운전을 그대로 가능하다는 것이다.

 

 공연 무대에 있어서도 역할안에 들어가는 배우는 다른 배우로도 대체가 가능하며, 이 뜻이 유연하고 변경이 용이하다는 것이다. 줄리엣의 객체가 다른 것으로 대체되어도 이는 로미오에 영향을 미치지 않으며, 줄리엣의 역할은 다른 객체가 대체할 수 있다.

 

역할과 구현을 분리

역할과 구현으로 구분하면 세상이 단순해지고, 유연해지며 변경도 편리해진다.


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

 

자바 언어

 

핵심은 구현보다 역할을 담당하는 인터페이스 더 중요하다는 것이다.

 

객체의 협력이라는 관계부터 생각해야 함

혼자 있는 객체는 존재하지 않음

클라이언트는 요청하고, 서버는 응답하며, 수 많은 객체 클라이언트와 객체 서버는 서로 협력 관계를 가짐

 

 

자바 언어의 다형성

 

위 그림에서 멤버 서비스가 인터페이스에 해당 메서드를 요청 했을 때 연결되어 있는 리포지토리의 메서드를 호출하는 것이 오버 라이딩

 

이처럼 다형성으로 인터페이스를 구현한 객체를 실행 시점에서 유연하게 변경할 수 있음

(메모리 멤버 리포지토리 혹은 jdbc리포지토리 중 하나를 선택해서 실행할 수 있다는 것)

 

 

클라는 인터페이스인 MemberRepository를 의존하고, 이 인터페이스를 구현한 

 

 

위에서 본 2개의 리포지토리를 할당할 수 있음

 

 

이런 식으로 - 다형성이기 때문

 

 

당연한 말로 부모 인터페이스와 전혀 관련이 없는 것은 할당할 수 없음

 

 

그래서 결과적으로 내가 선택한 리포지토리가 호출되어 할당되는 것

 

다형성의 본질

 

역할과 구현의 분리를 정리하자면 아래와 같다.

 

 

하지만 한계점도 존재한다.

 

 

스프링과 객체 지향

 

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


좋은 객체 지향 설계의 5가지 원칙을 정리한 것

 

 

SRP 단일 책임 원칙

 

계층을 적절하게 잘 나누는 것이 중요하다.

 

OCP 개방-폐쇄 원칙

이 원칙이 가장 중요한 원칙이라고 볼 수 있다.

 

 

확장에는 열려있고, 변경에는 닫혀있게 한다는 것은 예를 들어 인터페이스가 있고, 이를 구현하는 다른 클래스를 만드는 것은 기존 코드에 영향을 주는 것이 전혀 아니라는 것을 생각해 볼 수 있다. 

즉, 다형성을 연관지어 생각해보면 어느정도 이해할 수 있다.

 

 

하지만 이 경우를 보면 다른 구현체로 바꾸기 위해서 기존의 로직을 바꿔야 하는 것을 확인할 수 있다. 즉 OCP가 안지켜진 것이다.

 

OCP의 문제점은 

 

 

여기서 별도의 설정자를 스프링이 해주는 것 - DI 등의 필요성이 여기에 있음

 

LSP 리스코프 치환 원칙

 

간단하게 얘기하면 인터페이스가 있고, 구현체가 있다. 인터페이스의 규약에서 액셀은 앞으로 가도록하는 기능인데, 이를 무시하고 뒤로 가도록 하면 LSP를 어기게 되는 것

 

ISP 인터페이스 분리 원칙

 

DIP 의존관계 역전 원칙

이 또한 굉장히 중요한 원칙

 

 

클라이언트 코드가 인터페이스만 보라는 뜻이다.

 

 

 

위의 코드를 말하는 것

 

이 코드를 보면 MemberService는 인터페이스는 MemberRepository 필드를 가지고 있지만 new로 MemoryMemberRepository를 할당했다. 

이렇게 되면 MemberService는 MemoryMemberRepository에도 의존하고 있는 것이다.

의존한다는 것의 의미를 저 코드를 안다는 것이다. (알기만 하면 그냥 다의존)

 

따라서 MemberService는 추상화 인터페이스인 MemberRepository만 의존하는 것이 아니라 구현 클래스를 직접 선택하면서 MemoryMemberRepository까지 의존하게 되었고 DIP가 위반되는 것이다.

 

정리

 

객체 지향 설계와 스프링


스프링에 객체 지향에 대한 이야기가 많이 나오는 이유는 아래와 같다.

 

 

정리


 

모든 설계에 인터페이스를 부여했을 때의 장점은 어떤 데이터베이스를 사용할지 정하지 않아도, 나중에 쉽게 변경이 가능하다는 것이다. 또한 할인 기능을 구현한다고 했을 때 정확한 할인 정책이 정해지지 않아도 인터페이스를 사용해서 간단한 정책을 만들어 놓고 개발을 하다가 나중에 확장시키면 된다.

 

즉, 인터페이스를 먼저 설계하고 구현 방식을 나중에 정하면 구현 방식이 바뀌더라도 변경할 것이 적고 변경이 유연해진다.

 

실무에서의 고민

 

즉, 미래에 확장 가능성이 있다면 시작부터 인터페이스를 설정하고, 그렇지 않으면 그냥 바로 구체 클래스를 직접 사용한다.

728x90