본문 바로가기
Frameworks/Springboot

[Springboot] 좋은 객체 지향 프로그래밍과 스프링

by 젊은오리 2022. 7. 20.
728x90

[김영한님의 스프링 핵심 원리-기본편을 학습 후 정리한 내용입니다.]

객체지향 프로그래밍이란?

대학교 전공수업에서 보통 우리는 객체지향프로그래밍이라는 단어를 접하게 된다. 자바라는 언어를 배울 때, 자바라는 언어는 객체지향적인 언어라는 것을 알게된다. 다양한 클래스를 만들어서 객체를 생성하고, 그 객체 사이의 연결, 교류하여 프로그래밍하곤 하는데, 바로 이런 객체 지향 프로그래밍 기법을 도와주는 것이 바로 스프링 프레임워크이다. 객체 지향 프로그래밍을 하기 위해 서는 캡슐화, 추상화, 상속, 다형성을 잘 이해하고 있어야 한다.  그 중, 객체 지향 패러다임 중 가장 핵심이라고 할 수 있는 다형성이라는 특징을 잘 이해하고, 사용해야 한다. 이제 다형성이라는 것에 대해 알아보자. 

 

다형성 (Polymorphism)

다형성이란 여러 형태를 받아들일 수 있는 성질, 혹은 상황에 따라서 의미를 다르게 부여할 수 있는 특성이다.

쉽게 예를 들어보면, 집에 220V짜리 콘센트가 있다고 생각해보자. 우리는 그 220V에 맞는 가전제품이면 뭐든지간에 콘센트에 꼽아서 사용가능하다. 즉, 이런 220V하나만 있으면 냉장고 뿐만 아니라 김치냉장고, 세탁기 등을 모두 사용할 수 있게 된다. 자바언어에 대입해보면, 220V짜리 콘센트는 인터페이스(추상클래스)라고 하며, 냉장고, 김치냉장고, 세탁기를 구현클래스라고 볼 수 있다. 이런식으로 생각해보면, 세상의 표준 인터페이스들은 220V콘센트처럼 "다형성"을 따른다고 볼 수 있을 것이다. 그렇다면 이제 좋은 객체지향 설계의 5가지 원칙(SOLID)에 대해 알아보자.

 

SOLID원칙

1. SRP(단일 책임 원칙) Single responsibility principle

  • 한 클래스는 하나의 책임만 가져야 한다.
  • 하나의 책임이라는 것이 굉장히 모호해보인다. 이는 상황에 따라 뜻이 달라지므로 기준이 필요할 것이다. 여기서 말하는 중요한 기준은 바로 "변경"이다. 변경이 있을 때 파급효과가 적으면 SRP를 따른다고 볼 수 있다. 
  • 쉽게 예를 들어서 UI를 변경했는데 Service나 Domain상에서 코드를 변경해야 하는 일이 벌어진다면?? SRP를 제대로 따른다고 볼 수 없을 것이다.

 

2. OCP(개방-폐쇄 원칙) open/closed principle

  • 소프트웨어 요소는 확장에는 열려있지만 변경에는 닫혀있어야 한다.
  • 이는 다형성을 활용하라는 말과 동일시된다. 인터페이스를 구현한 새로운 클래스를 하나 만들어서 기능을 구현하게 되면 기존의 코드는 변경하지 않았지만 새로운 기능을 추가하여 확장했다고 볼 수 있다.
  • 하지만 여기서 문제점이 있다. 우리가 인터페이스를 따르는 구현클래스를 새로 하나 만들었지만 이 구현클래스를 실제로 사용하기 위해서는 Service(클라이언트)단에서 구현클래스를 직접 선택할때, 코드를 변경해야 한다.
  • 예를 들어서 Service클라이언트가 A_Repository에 의존하다가 B_Repository를 의존하려고 할때, 다음의 변경이 생긴다.
  • ex) 기존코드 : Repository m = new A_Repository();  변경코드 : Repository m = new B_Repository();

결국 이 문제를 해결하려면 별도의 설정이 필요하다.

 

3. LSP(리스코프 치환 원칙) Liskov substitution principle

  • 다형성에서 하위클래스는 인터페이스 규약을 다 지켜야 한다. 
  • 이는 내가 만든 구현클래스가 컴파일을 성공했다했더라도 인터페이스 규약을 지키지 않으면 LSP를 위반한 셈이다. 쉽게 예를 들어서, 자동차 인터페이스의 엑셀이라는 기능은 느리더라도 앞으로 가야하는 기능이다. 만일 뒤로 가게 만들었다면 LSP위반이 된다.

 

4. ISP(인터페이스 분리 원칙) Interface segregation principle

  • 특정 클라이언트를 위한 인터페이스 여러개가 범용 인터페이스 하나보다 낫다.
  • 예를 들어서, 자동차 인터페이스를 (운전 인터페이스, 정비 인터페이스)로 분리하는 것이 관리에 용이해질 뿐 아니라 인터페이스의 기능들이 명확해지고, 대체가능성을 높일 수 있다는 장점이 있다.

 

5. DIP(의존관계 역전 원칙) Dependency inversion principle

  • 구체화에 의존하지 말고 추상화에 의존해라.
  • 쉽게 말하면 구현클래스에 의존하지 말고 인터페이스에 의존하라는 뜻이다.
  • 하지만 여기서 OCP와 마찬가지로 문제점이 발생한다. DIP역시 Service(클라이언트)가 구현클래스를 직접 선택하는 과정에서 인터페이스와 구현클래스를 동시에 의존하게 된다.
  • ex) Repository m = new A_Repository();   //Repository: 인터페이스, A_Repository: 구현클래스

결국 이 문제를 해결하려면 별도의 설정이 필요하다.

 

정리

객체 지향의 핵심은 바로 다형성이다. 하지만 다형성만으로는 이상적인 객체지향 방법으로 개발할 수 없다. 즉, 구현 객체를 변경할 때 클라이언트 코드도 함께 변경해야 한다.(OCP, DIP 위반) 우리가 스프링을 사용하는 이유는 바로 여기에 있다. 스프링은 DI(의존성 주입), DI컨테이너를 제공함으로써 다형성, OCP, DIP를 가능하게 지원해준다. 따라서 클라이언트 코드의 변경없이 기능을 확장하고, 인터페이스만을 의존하면서 쉽게 부품을 갈아 끼우듯이 개발할 수 있다.

728x90

댓글