본문 바로가기

SPRING/영한님 강의 - 스프링 핵심원리 기본편

좋은 객체 지향 프로그래밍이란 무엇일까(다형성, SOLID)

현재 포스팅은 영한님의 스프링의 핵심원리 - 기본편을 바탕으로 작성한 포스팅입니다 :)

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%ED%95%B5%EC%8B%AC-%EC%9B%90%EB%A6%AC-%EA%B8%B0%EB%B3%B8%ED%8E%B8

 

스프링 핵심 원리 - 기본편 - 인프런 | 강의

스프링 입문자가 예제를 만들어가면서 스프링의 핵심 원리를 이해하고, 스프링 기본기를 확실히 다질 수 있습니다., 스프링 핵심 원리를 이해하고, 성장하는 백엔드 개발자가 되어보세요! 📢

www.inflearn.com

 

객체란 프로그램에서 사용되는 값을 저장할 변수와, 작업을 수행할 메서드를 서로 연관된것들끼리 묶어서 만든 것입니다.

 

스프링은 자바 언어 기반의 프레임워크로, 자바의 객체 지향적 특징을  잘 살려 좋은 객체 지향 애플리케이션을 개발할 수 있게 도와주는 프레임워크입니다. 객체 지향 프로그래밍(Object Oriented Programming, OOP)은 프로그래밍에서 필요한 데이터를 추상화 시켜 상태와 행위를 가진 객체로 만들고, 객체들 간의 상호작용을 통해 로직을 구성하는 프로그래밍 방법입니다.

 

이러한 객체 지향 프로그래밍인 유연하고 다형성(변경에 용이)하게 만들기 때문에 대규모 소프트웨어 개발에 많이 사용됩니다! 그렇다면 다형성이란 무엇일까요???

 

다형성에 대해 이해해보기 전 우선 용어적으로 간단히 살펴보자면, 하나의 객체가 여러 가지 타입을 가질 수 있는 것을 뜻합니다.

 

이해를 위해 이 세상을 역할(인터페이스)구현(인터페이스를 구현한 객체)로 구분해보겠습니다!

 

 

테슬라를 운전하는 사람의 차가 아반떼나 K3로 바뀌었다고 가정해 보겠습니다. 이때 운전자는 새로운 차 운전을 위해 새로 운전을 배워야 할까요?? 그렇지 않습니다 :)

 

왜냐하면 자동차 역할이라는 일종의 인터페이스를 바탕으로 자동차(인터페이스 구현체)들을 만들었기 때문입니다. 즉 운전자는 자동차의 역할이라는 인터페이스에만 의존하고 있기에, 인터페이스를 바탕으로 만든 새로운 차가 나와도 운전자에게 영향을 미치지 않는 것이죠

 

만약 로미오와 줄리엣 연극을 하는 당일 4명의 배우가 아프다면 무명 배우로라도 대체할 수 있어야 겠죠?

대본을 장동건, 김태희와 같이 실명을 바탕으로 만들었다면(== 구현체에 의존) 배우를 바꾸는 것 뿐 아니라 대본 까지 바꾸어야 합니다. 하지만 로미오와 줄리엣에 (== 인터페이스) 의존하여 대본을 짰다면 배우가 대체되더라도 대본을 바꿀 필요가 없겠죠 :)

 

즉 이를 프로그래밍에 대입해보자면, 역할(인터페이스)와 구현(인터페이스 구현체)를 구분하여 프로그래밍을 함으로써 변경에 유연한 코드를 짤수 있는 것입니다!

 

객체 지향 프로그래밍에서 객체를 설계 시, 인터페이스와 구현체를 명확히 분리하기 위해  우선 인터페이스를 설계하고 그 인터페이스(역할)를 수행하는 구현 객체를 만들게 됩니다.

 

앞서 제가 객체 지향 프로그램란 객체의 협력을 바탕으로 한 개념이라고 했었죠?? 즉 수많은 객체는 각자 클라이언트와 서버의 위치에서 서로 협력하게 됩니다.

여기에 지금까지 설명드린 다형성 개념을 적용해보자면 다형성이란 클라이언트를 거의 변경하지 않고 서버의 구현 기능을 유연하게 변경할 수 있는 것입니다. 즉 확장 가능한 설계를 하는것이죠!

 

위와 같은 상황에서 Memory DB에서 jdbc로 바꾸어도 클라이언트 쪽 코드는 거의 변경할 필요가 없는 것이죠

@RequiredArgsConstructor
public class MemberService{
	private final MemberRepository memberRepository;
    ...
}

JdbcMemberRepsitory로 변경하고 싶다면 jdbc만을 Bean으로 등록한다면 스프링에서 알아서 DI를 해주게 됩니다!


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

클린 코드로 유명한 로버트 마틴은 좋은 객체 지향 설계의 5가지 원칙을 정의하였습니다

 

  • SRP : 단일 책임 원칙(Single Responsibility Principle)
  • OCP : 개방-폐쇄 원칙(Open/Closed Principle)
  • LSP : 리스코프 치환 원칙(Liskov Substitution Principle)
  • DIP : 의존 관계 역전 원칙(Dependency Inversion Principle)
  • ISP : 인터페이스 분리 원칙(Interface Segregation Principle)

SRP

단일 책임 원칙한 클래스가 하나의 책임만 가지도록 하는 원칙입니다. 이 원칙을 준수하면 각 클래스가 맡은 책임이 명확해져, 한 책임의 변경이 다른 책임에 미치는 영향을 최소화 할 수 있습니다.

 

OCP

개방-폐쇄 원칙은 소프트웨어 구성 요소가 확장에는 열려 있어야 하며, 변경에는 닫혀 있어야 함을 의미합니다. 즉, 새로운 변경 사항이 발생했을 때 직접적인 객체 수정 없이도 이를 반영할 수 있도록 설계해야 함을 의미합니다. 이를 지원하기 위해 스프링에서는 의존성 주입(DI)과 제어의 역전(IoC)을 제공합니다

 

LSP

리스코프 치환원칙은 객체는 프로그램의 정확성을 깨지 않으면서 하위 인스턴스로 바꿀수 있어야 한다는 원칙입니다.클라이언트는 인터페이스를 구현한 객체의 내부 구현을 알지 못하므로, 객체는 인터페이스의 명세를 준수하여 구현되어야 합니다. 예를 들어, '자동차' 인터페이스에 '앞으로 가는 기능'을 선언했는데, 이를 '뒤로 가게' 구현한 것은 LSP를 위반한 예입니다. 느리더라도 '앞으로 가는 기능'을 제공해야 LSP를 준수한 것입니다.

 

ISP

인터페이스 분리 원칙특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 나음을 의미합니다.예를 들어, '전자기기'라는 인터페이스에 '켜기', '끄기', '충전하기', '인쇄하기'라는 메소드가 있다면, '스마트폰' 클래스는 '인쇄하기' 메소드를 사용하지 않을 것입니다. 이럴 때 '스마트폰'을 위한 '켜기', '끄기', '충전하기' 메소드만을 가진 인터페이스와 '인쇄하기' 메소드를 가진 인터페이스로 분리하는 것이 더 효과적일 수 있습니다. 이렇게 하면 각 클래스는 필요한 메소드만을 포함한 인터페이스에 의존하게 되므로 더 명확하고 깔끔한 설계를 할 수 있습니다.

 

DIP

의존관계 역전 원칙은 프로그래머가 구체적인 것보다 추상화된 것에 의존해야 함을 의미합니다. 즉, 클라이언트가 구현 객체에 직접 의존하는 것이 아니라, 클라이언트와 구현 객체 모두 인터페이스에 의존해야 합니다. 이렇게 되면 구현 객체가 변경되더라도 클라이언트에는 아무런 변화가 없게 됩니다.