[JAVA 개념정리] SOLID - 객체지향 설계의 5원칙

Doyeon·2023년 1월 25일
0

JAVA 개념정리

목록 보기
12/13
post-thumbnail
post-custom-banner

SOLID - 객체지향 설계의 5원칙

  • SRP : 단일 책임 원칙(Single reponsibility principle)
    • 한 클래스는 하나의 책임만 가져야 한다.
  • OCP : 개방-폐쇄 원칙(Open/closed principle)
    • 소프트웨어 요소는 확장에는 열려 있으나, 변경에는 닫혀 있어야 한다.
  • LSP : 리스코프 치환 원칙(Liskov substitution principle)
    • 프로그램 객체는 프로그램의 정확성을 깨뜨리지 않으면서, 하위 타입의 인스턴스로 바꿀 수 있어야 한다.
  • ISP : 인터페이스 분리 원칙(Interface segregation principle)
    • 특정 클라이언트를 위한 인터페이스 여러 개가 범용 인터페이스 하나보다 낫다.
  • DIP : 의존관계 역전 원칙(Dependency inversion principle)
    • 추상화에 의존해야지, 구체화에 의존하면 안된다.
✔️ 학습순서 SRP → DIP → OCP → LSP → ISP

단일 책임 원칙

Single Responsibility principle, SRP

“어떤 클래스를 변경해야 하는 이유는 오직 하나뿐이어야 한다” - 로버트 C. 마틴

  • 단 하나의 책임을 갖는 객체
  • ex) 계산기
    • 더하기, 빼기, 곱하기, 나누기 연산 기능별로 연산 클래스를 구현한다.

개방-폐쇄 원칙

Open-Closed Principle, OCP

“소프트웨어 엔티티(클래스, 모듈, 함수 등)는 확장에 대해서는 열려 있어야 하지만, 변경에 대해서는 닫혀 있어야 한다.”

  • ex) Java의 Database 연결
    • 데이터베이스 접속을 도와주는 JDBC API
    • 개발 과정에서 데이터베이스 변경하더라도 개발 코드 전부 수정할 필요 없음
    • 연결할 때 필요한 ID, PWD, URL등 설정 담당 부분만 변경하면 된다.
  • ex) 자동차
    • [원칙 위반]
      • 운전자 → 마티즈(창문수동, 기어수동)
      • 운전자 → 소나타(창문자동, 기어자동)
      • 기어 수동, 자동에 따라 운전자의 행동이 달라진다. 변화가 생길 때 운전자에게 바로 영향
    • [원칙 적용]
      • 운전자 → 자동차(창문조작, 기어조작)
      • 자동차 ← 마티즈(창문조작, 기어조작) / 자동차 ← 소나타(창문조작, 기어조작)
      • 다양한 자동차가 생겨도 운전자의 행동은 똑같다.
      • 자동차 입장에서는 자신의 확장에 개방, 운전자 입장에서는 주변의 변화에 폐쇄
  • ex) 계산기
    • [원칙 위반]
      • 기능 확장할 때 마다 기존코드 수정
      • if else 블록 자주 등장
      • 기능 확장을 위한 코드 수정 시, 여러 클래스에서 다발적으로 진행
    • [원칙 적용]
      • 변화되는 부분을 추상화해서 변화를 고정
      • 기능 추가될 때 클래스의 상속을 통해 하위 클래스에서 기능 구현
      • 기존코드 수정하지 않아도 객체 상속 다형성 원리에 의해 기능 확장
      • 연산 클래스는 추상화된 부모 클래스를 상속받아 기능별로 구현

리스코프 치환 원칙

Liskov Substitution Principle, LSP

“서브 타입은 언제나 자신의 기반 타입(base type)으로 교체할 수 있어야 한다.”

  • 하위 클래스의 인스턴스는 상위형 객체 참조변수에 대입해 상위 클래스의 인스턴스 역할을 하는 데 문제가 없어야 한다.
  • ex) 계층도(조직도)와 분류도
    • [원칙 위반] - 계층도(조직도)
      • 아버지 ← 딸, 아들
      • 딸이 아버지의 역할을 할 수 없다.
    • [원칙 적용] - 분류도
      • 조류 ← 참새, 까치
      • 참새, 까치는 조류 역할을 할 수 있다.
  • ex) 계산기
    • [원칙 위반]
      • 추가적 기능이 필요한 자식 클래스가(DivideOperation) 존재
      • 자식 클래스의 인스턴스가 부모 클래스의 인스턴스 역할을 수행한다고 볼 수 없음
    • [원칙 적용]
      • 부모와 자식 클래스 사이의 행위가 일관성 있도록 추상화 더 정교하게 구현
      • 연산 기능을 추상화한 부모 클래스에 피연산자 값의 유효성 검사를 진행하는 메서드(isInvalid) 추가
      • 계산기 클래스에서는 isInvalid 사용하여 유효성 검사 진행
      • 이 유효성 검사가 필요한 자식 클래스에서는 isInvalid 조건 구체화

인터페이스 분리 원칙

Interface Segregation Principle, ISP

“클라이언트는 자신이 사용하지 않는 메서드에 의존 관계를 맺으면 안 된다.”

  • 특정 클라이언트를 위한 인터페이스 여러개가 범용 인터페이스 하나보다 낫다.
  • 클라이언트가 필요하지 않는 기능을 가진 인터페이스에 의존해서는 안되고 최대한 인터페이스를 작게 유지해야 한다.
  • 상위 클래스는 풍성할수록 좋다.
    • 풍성할수록 하위 클래스에 많은 기능 확장시키고, 형변환, 코드중복을 줄인다.
  • 인터페이스 내 메소드는 최소한일수록 좋다.
    • 인터페이스는 하위 클래스에게 구현을 강제하는 역할. 최소한의 기능만 제공하면서 하나의 역할에 집중
  • ex) 계산기
    • [원칙 위반]
      • 필요하지 않은 기능 강제 구현
      • 필요하지 않은, 사용 못 하는 기능이 강제 구현되어 사용하지 못하도록 예외처리 해야하는 상황 발생
    • [원칙 적용]
      • 필요하지 않은 기능을 강제 구현하지 않도록 인터페이스 분리
      • 연산 결과 보여주는 방법마다 인터페이스 구현

의존성 역전 원칙

Dependency Inversion Principle, DIP

“고차원 모듈은 저차원 모듈에 의존하면 안 된다. 모두 다른 추상화된 것에 의존해야 한다.”
”추상화된 것은 구체적인 것에 의존하면 안 된다. 구체적인 것이 추상화된 것에 의존해야 한다.”
”자주 변경되는 구체(Concrete) 클래스에 의존하지 마라”

  • 세부적인 사항은 추상화에 의존해야 한다.
  • ex) 자동차와 타이어
    • [원칙 위반]
      • 자동차 → 스노우타이어
      • 자동차 자신보다 더 자주 변하는 스노우타이어에 의존하면 좋지 않다. 스노우타이어가 변할 때 마다 자동차가 영향을 받는다.
    • [원칙 적용]
      • 자동차 → 타이어 ← 스노우 타이어 / 일반 타이어 / 광폭 타이어
      • 자동차가 구체적인 타이어가 아닌 추상화된 타이어 인터페이스에만 의존
      • 타이어가 변경되어도 자동차가 영향을 받지 않는다.
  • ex) 계산기
    • [원칙 위반]
      • 계산기(고수준 모듈)가 개별 연산 클래스(저수준 모듈)을 포함하여 계산 기능을 구현
      • 연산 클래스에 의존
    • [원칙 적용]
      • 고수준 모듈 변화되는 부분 추상화
      • 저수준 모듈 추상화에 의존시키기
      • 계산기 클래스에 추상화된 부모 클래스 포함시키기
      • 연산 클래스는 추상화된 부모 클래스를 상속받아 기능별로 구현하기

[참고]
[Java] 객체지향 설계 5원칙 - SOLID
[Java] 객체지향 설계 5원칙 - SOLID란 무엇일까?

profile
🔥
post-custom-banner

0개의 댓글