관리 메뉴

JIE0025

[객체지향] SOLID 원칙 본문

백엔드 부트캠프/+

[객체지향] SOLID 원칙

sdoaolo 2022. 12. 6. 16:53
728x90

 

 

✅  객체지향 설계 원칙

 

⏺ 객체지향 설계 원칙이란?

유지보수하기 쉽고, 유연하고, 확장이 쉬운 SW를 만들기 위한 원칙

코드베이스, 아키텍처 설계에까지 다양하게 적용할 수 있다.

 

 

높은 응집력

비슷한 일을 하는 기능 - 하나의 책임에 포함되는 기능들이 잘 뭉쳐있음.

하나의 기능을 변경하는데 변경해야할 곳이 많으면 응집력이 낮은 것임.

 

 낮은 결합도

클래스간 의존성이 낮을 떄 낮은 결합도를 가진다.

하나의 클래스를 수정하는데 의존하는 다른 클래스를 모두 수정해야하면 결합도가 높은것.

 

 

 

✅  SOLID 원칙

  •  S RP: Single Responsibility Principle. 단일 책임 원칙
  •  O CP: Open-Closed Principle. 개방-폐쇄 원칙
  •  L SP: Liskov Substitution Principle. 리스코프 치환 원칙
  •  I SP: Interface Segregation Principle. 인터페이스 분리 원칙
  •  D IP: Dependency Inversion Principle. 의존성 역전 원칙

 

 

1️⃣ SRP: Single Responsibility Principle.    단일 책임 원칙

클래스가 제공하는 기능들은, 하나의 책임을 수행하는데 집중해야 한다.

  • 한 클래스는 단 한 가지의 변경 이유만을 가져야 한다.
  • 하나의 모듈은 하나의, 오직 하나의 액터에 대해서만 책임져야 한다.
  • 컴포넌트를 변경하는 이유는 오직 하나뿐이어야 한다.

 

단일 책임원칙 위반 코드

print와 log는 우리가 라는 고양이의 기능이 아님  -> 빼주어야함.  (다른 방법으로 구현해야한다) 

 

고양이에 관련된 함수들만 남겨준 다음

고양이 상태를 return하는 메서드를 만들고,

호출하는 쪽에서 출력하고 로그를 만들어주면 됨!  

 

 

SRP를 잘 지키면,

  • 응집력이 높아지고 결합도가 낮아짐
  • 코드 가독성이 좋아짐
  • 테스트 범위가 작아짐

 


 

2️⃣ OCP: Open-Closed Principle.    개방 폐쇄 원칙

확장에 대해선 개방, 수정에 대해선 폐쇄해야한다.

 

 

개방 폐쇄 원칙 위반 코드

  • 초반에 고양이와 강아지만 있었는데, 소와 양을 추가해달라는 요청이 들어왔음 
    • hey를 호출했을 때 오류가남.
    • 수정은 close 안해줘야하는데 수정이 필수적인 코드가 됨. (개방 폐쇄 원칙을 위반함)

 

 

확장에 대해 open, 수정에 대해 close된 코드

  • 양과 소를 추가 (확장)이 자유롭게 가능함 (open)
  • hey 함수에 대해 수정할 필요가 없음 (close)
  • 인터페이스를 이용해 상속받는 클래스들을 가짐으로써 확장에 열려있고, 수정에 닫혀있는 구조를 만들수 있었다.
  • 100개 1000개의 확장이 일어나도 hey는 수정할 필요가 없다.

 


 

3️⃣ LSP: Liskov Substitution Principle.   리스코프 치환 원칙

object T가 있고, T를 상속받는 s1, s2, s3가 있을 때

T를 서브타입 object (s1,s2,s3)로 바꿔도, 우리가 원하는대로 동작해야한다

 

리스코프 치환 원칙 위반 코드

Cat을 상속받는 Fish 클래스를 만들었다.

cat을 서브타입인 Fish()로 바꿨더니 meow를 말하지 않는다. (원하는대로 동작하지 않는다)

===  리스코프 치환원칙이 위반되었다.

 


 

4️⃣ ISP: Interface Segregation Principle.   인터페이스 분리 원칙

너무 큰 인터페이스를 만들면  사용하지 않는 기능들이 생김 

분리해서, 작은 인터페이스를 가질것!!! 

 

  • 인터페이스의 단일 책임을 위한 원칙이다
  • 즉, 일반적인 하나의 인터페이스를 조금 더 구체적인 인터페이스로 쪼개는것이 낫다

 

인터페이스 분리 원칙 위반 코드

 

  • 만약 수중자동차 인터페이스를 만들었다 가정하자. 수중자동차는 자동차의 역할도, 보트의 역할도 수행해낸다.
  • 이 수중자동차 인터페이스로 자동차인 제네시스를 구현하면 어떻게 될까?
    • 사용되지 않는 메서드가 생겨난다. 

 

 

일반적인 하나의 인터페이스를 조금 더 구체적인 인터페이스로 쪼개는것이 낫다는 인터페이스 분리원칙을 적용하면

자동차 인터페이스와 보트 인터페이스로 분리해서

car 클래스는 Icar를 구현, boar 클래스는 IBoat를 구현, 수중자동차의 경우는 ICar, IBoat를 모두 구현하면 된다.

 

 


 

5️⃣ DIP: Dependency Inversion Principle.   의존성 역전 원칙

상위 수준의 모듈은 하위 수준의 모듈에 의존해서는 안 된다.

둘 모두 추상화에 의존해야 한다.

 

추상화는 구체적인 사항에 의존해서는 안 된다. 구체적인 사항은 추상화에 의존해야 한다

High level이 low level 에 의존,  dependency를 갖게 되면,,, 수정이 어렵다.

 

아래 코드를 보자

의존성 역전 원칙 반 코드

  • 상위 레벨인 Zoo가 Cat, Dog에 Dependency를 갖고있다. 
  • 여기에서 Sheep , Cow를 추가하게 되면 Zoo는 더많은 의존성을 추가하게 된다.
  • dependency가 증가하면 코드 수정과 관리가 어려워진다.

 

 

이를 해결하기 위해 Dependency Inversion을 사용한다.

High level(Zoo)과 Low Level(Cat, DOg...) 사이에   Abstract 모듈인 Animal을 추가한다.

 

 

Cat, Dog는 Animal을 상속받고 있고, 

Zoo는 animal에 dependency가 있으므로, Cow, Sheep이 추가되어도  동물원은 건들일 필요가 없게 된다!

 

 

 

 

예시2

 

초콜릿을 갈아끼는게 아니라, 파인트 라는 고수준 모듈도 다 수정을 해줬어야했음

 

 

 

IOC를 제어의 역전을 위해 DI의존관계 주입이 사용되는것이고, 
DIP 의존 역전 원칙을 만들기 위해 사용되는게 DI기도 함.

 

 


 

  SOLID 요약

  원칙 설명
SRP:
Single
Responsibility
Principle. 
단일 책임 원칙 클래스가 제공하는 기능들은, 하나의 책임을 수행하는데 집중해야 한다.
OCP:
Open-Closed
Principle. 
개방-폐쇄 원칙
확장에 대해선 개방, 수정에 대해선 폐쇄해야한다
  • 양과 소를 추가 (확장)이 자유롭게 가능함 (open)
  • 동물을 호출하는 hey 함수에 대해 수정할 필요가 없음 (close)
  • 인터페이스를 이용해 상속받는 클래스들을 가짐으로써 확장에 열려있고, 수정에 닫혀있는 구조를 만들수 있었음
LSP:
Liskov
Substitution
Principle. 
리스코프 치환 원칙 object T가 있고, T를 상속받는 s1, s2, s3가 있을 때
T를 서브타입 object (s1,s2,s3)로 바꿔도, 원하는대로 동작해야한다
ISP:
Interface
Segregation
Principle. 
인터페이스 분리 원칙
인터페이스의 단일 책임을 위한 원칙
일반적인 하나의 인터페이스를 조금 더 구체적인 인터페이스로 쪼개는것이 낫다

== 클라이언트가 자신이 이용하지 않는 메서드에 의존하지 않아야 한다


DIP:
Dependency
Inversion
Principle. 
의존성 역전 원칙 상위 수준의 모듈은 하위 수준의 모듈에 의존해서는 안 된다.
>> 둘 모두 추상화에 의존해야 한다.

추상화는 구체적인 사항에 의존해서는 안 된다. 구체적인 사항은 추상화에 의존해야 한다

 

 

 

 

 

 

글에 자바로도 원칙들을 실습해보고 업데이트를 해야겠다.

 

 

 


 

references