Web/Spring

좋은 객체지향이란? (5가지 원칙)

Spring을 제대로 시작하기 전에 좋은 객체지향이 무엇인지 뇌에 때려박고 시작해야할 것 같아서 정리해보았다.

솔직히 Java로 객체지향을 엄격히 지켜 프로그래밍 한 적은 거의 없었다.

혼자서 개발하다보니 굳이? 라는 생각에 java나 c++로 코드를 작성할때도 그냥 c언어 처럼 작성했다.

java나 c++은 그냥 라이브러리 제공하는 언어정도?

그런데 c언어나 django로 프로젝트를 진행했을때 몇가지 불편한 점을 느꼈다.

c언어로 작성할때 아무리 함수로 나눈다고 하더라도 스파게티 소스가 되어 버리고,

django에서 친구와 협업할때도 서로의 개발 영역이 구분이 되지 않았다.

그런데 아이러니하게도 내가 귀찮아서 하지 않던 객체지향프로그래밍이 이런 문제들을 해결하기 위해 나온 방법론이었다..ㅋ

이제야 뒤늦게 객체지향의 필요성을 뼈저리게 느끼고 "객체지향설계를 잘하는 개발자"로 제대로 성장해보려고 한다.

 

좋은 객체지향은 아래 5가지의 원칙이 잘 지켜진 프로그램을 말한다.

 

로버트 마틴의 '좋은 객체지향 설계의 5가지 원칙'


  1. SRP : 단일 책임 원칙 (Single Responsiblility Principle)
  2. OCP : 개방-폐쇄 원칙 (Open/Closed Princlple)
  3. LSP : 리스코프 치환 원칙 (Liskov Substitution Principle)
  4. ISP : 인터페이스 분리 원칙 ( Interfacle Segregation Principle)
  5. DIP : 의존관계 역전 원칙 (Dependency inversion Principle)

spring을 공부하기 전부터 spring 개발자 톡방에서 익히 들은 단어가 OCP와 DIP였다.

어디선가 들어봤던 것들인데 이번 기회에 개념을 제대로 챙기고 가야겠다.

 

1. SRP : 단일 책임 원칙


하나의 클래스는 하나의 책임만 가져야 한다.

 

그러나 문맥과 상황에 따라 다르다.

 

"변경"이 있을때 파급효과가 적으면 SRP를 잘 따른다고 할 수 있다.

 

 

 

2. OCP : 개방-폐쇄 원칙


확장에는 열려있으나, 변경에는 닫혀있어야 한다.

 

이 말의 의미는 어떤 기능을 추가할때 변경은 하지않고 확장으로만 해야한다는 뜻이다.

OCP를 만족하기 위해서 객체지향프로그래밍의 "다형성"을 이용한다. (Overloading, Overriding)

 

예를들어, 상품주문 서비스를 이미 구현했다고 했을때 "할인쿠폰적용"이라는 기능을 추가하기 위해서는

기존 메소드안에 있는 코드를 "변경"하는 것이 아닌 Overloading이나 Overriding을 이용해서 "확장"시키라는 의미이다.

 

그러나 문제점이 존재한다.

상품주문하는 메소드에서 할인쿠폰을 선택할지, 말지에 대한 코드 변경이 불가피 하다는 것이다.

 

 

 

OCP를 위해 다형성을 이용했지만 OCP를 다시 만족하지 못하는 모순이 발생한다.

이를 해결하는 방법은 구현 클래스에서는 추상화에 의존하게 한 후 생성자로 어떤 구현체를 받을지 선택하게 하고

AppConfig class (구성 클래스)를 새로 만들어서 어떤 구현체를 선택할 지 '생성자를 통해 주입' 한다.

(이를 생성자 주입 이라고 한다.)

 

 

 

3. LSP : 리스코프 치환 원칙 


 

실제 정의 : 

  • 타입 S의 객체 o1 과 타입 T의 인스턴스 o2가 있을 때, 어떤 프로그램에서 타입 T의 객체로 P가 사용된다고 하자. S가 T의 서브타입이라면 P에 대입된 o1이 o2로 치환 된다고 해도 P의 행위는 바뀌지 않는다. 

이해하기 쉽게 풀어쓴 정의 :

  • A 가 B 의 서브 클래스이면 서브클래스 A 의 인스턴스 파라미터가 B로 전달되었을때 B의 성질이 깨지면 안된다.

LSP가 지켜지지 않는다고 컴파일이 안되진 않는다.

하위클래스는 상위 클래스의 인터페이스 규약을 지켜야 한다.

클라이언트 입장에서는 이 인터페이스를 믿고 사용할 수 있도록 보장해주어야 하기 때문에 LSP가 필요하다.

 

예를들어 정사각형 객체가 있다고 하자.

정사각형 객체는 가로와 세로의 길이가 같아야 한다는 보장이 있어야하고, 클라이언트는 이 정사각형 객체에서 제공하는

인터페이스가 가로, 세로 길이가 맞다고 믿고 사용해야 한다.

그런데 정사각형의 하위 클래스에서 직사각형을 구현하면 가로,세로의 길이가 다른 파라미터가 전달되어 LSP가 깨질 수 있다.

 

 

4. ISP : 인터페이스 분리 원칙


인터페이스는 가능한 여러개로 분리한다.

단, 인터페이스를 분리해도 클라이언트에게 영향을 주지않아야한다.

( 기존에 클라이언트가 인터페이스를 사용하던 방식의 변화를 주지 않아야 한다. )

 

예시)

  • 자동차 인터페이스 -> 운전자 인터페이스, 정비사 인터페이스로 분리
  • 사용자 클라이언트 -> 운전자 클라이언트, 정비사 클라이언트로 분리

 

5. DIP : 의존관계 역전 원칙


프로그래머는 구체화에 의존하지 않고 추상화에 의존해야한다,

 

이해하기 쉽게 예를 들어서,

자동차가 K3인지, 아반떼인지, 벤츠e클래스 인지에 따라 운전방법이 바뀌면 안된다.

차종이 어떤것인지 (구체화)에 의존하지 않고 운전방법(추상화)(인터페이스)에 의존해야 한다.

 

이렇게 인터페이스에 의존하도록 하는것이 "의존성 주입"이다.

 

 

OCP에서 언급한 것과 같이 결국에는 추상화에 구현체를 연결해주어야 하는 문제가 생기기 때문에

구현 클래스에서는 추상화에만 의존하게 하고 생성자 주입을 통해 구현체를 연결해야 한다.

 

 

 

 

 

정리.


 

스프링을 배우기 전에 '객체지향'에 대해서 확실히 정리해봤다.

이 전까지 스프링은 단지 MVC 패턴을 위한 프레임워크인줄로만 알고있었지만,

사실 객체지향을 극한으로 다루기 위한 프레임워크였다.

 

 

 

다음으로.


스프링을 왜 배울까 부터 시작해서 객체지향의 어느부분을 스프링이 담당해야 할 지 알게되었다.

이제 순수 java코드로 구현했던 객체지향을 스프링으로 전환해볼 것이다.

 

 

 

 

 

 

출처 : [인프런] 김영한님의 스프링 핵심원리 - 기본편.

'Web > Spring' 카테고리의 다른 글

[boot+jpa실전 1] 1. 스프링부트 프로젝트 생성  (0) 2021.01.19
스프링 기초 정리  (0) 2021.01.18
웹 스코프 java.lang.IllegalStateException 에러 해결방법  (0) 2021.01.18
IoC, DI 용어정리  (0) 2020.12.31
객체지향이란?  (0) 2020.12.23