본문 바로가기
Design Pattern

SOLID란?

by 진꿈청 2024. 3. 11.

SOLID란 무엇일까?

흔히 객체지향적 설계를 얘기할 때 SOLID 원칙을 설명을 한다.

하지만, 이 원칙을 지키면 좋다는 것이지 위배했다고 무조건 최악의 코드가 되는 것은 아니다.

한번 SOLID의 요소에 대해 하나하나 알아보자.

 

1. S(SRP - Single Responsibility Principal - 단일 책임의 원칙)

 

SRP - Object - Class가 하나의 책임만을 가져야 함

 

예를 들어 아래와 같은 Add Class가 있다고 했을 때
여기에 곱하기 나누기를 넣으면 단일 책임의 원칙이 위배된다.

 

public class Add{
	public int add(int a, int b){
    	return a + b;
    }
    
    public static void main(String[] args){
    	System.out.println(add(1, 2));
    }
}

 

그런데 우리가 코드를 작성하다보면 2개의 책임이 포함되어 있는 클래스를 만들게 될 수도 있다.

이 경우 무조건 잘못된 것은 아니고 단일 책임의 원칙을 지키겠다는 마음가짐이 중요하다.

무조건 이렇게 해야 돼 보다는 최대한 단일 책임의 원칙을 지키며 프로그래밍하겠다는 마음가짐이 중요하다.

 

2. O(OCP - Open Close Principal - 개방 폐쇄 원칙)

 

이 원칙은 어떤 코드가 개방에는 오픈되어 있고 수정에는 닫혀 있다는 것을 말한다.

  • 개방 - Open
  • 수정 - Close

예를 들어 A라는 클래스를 만들어 테스트도 하고 실제로 서비스 하고 있다고 하자.

 

A.class -> Test -> 작동(서비스)

 

하지만 이때 수정이 필요한 경우

 

close - A.class(기능 보완) -> 고치자!(기존의 A 클래스를 수정하는 것)의 방법이 아니라

  • (기존의 클래스는 Close)

open - A-update.class -> 기능 보안 -> 해결(새로운 클래스를 만들어서 해결)

  • (새로운 클래스 생성은 Open)

즉, 정리하자면 기능 보완을 했을 경우 기존의 A.class를 수정하는 것이 아니라,

기능을 보완을 한 A-update.class 바꿔치기만 하면 된다.

 

 

그러나, 위의 형태로 구성을 하려면 추상화라는 것이 필요하다.

 

추상적인.class <- (구현, 상속) A.class

 

위의 형태로 구성되어 있을 경우 실행은 추상적인.class가 실행이 되지만,
동적 바인딩 돼서 A.class 또는 A-update.class가 실행이 되는 구조이다.

 

이때, 알아야 되는 것이 디자인 패턴이다.

디자인 패턴을 알아야 위와 같은 작업이 가능하다.

 

3. D(DIP - Dependency Inversion Principal - 의존성 역전 원칙)

 

이 원칙에 대한 설명으로 음식점을 예로 들겠다.

 

한 음식점에 홍길동이란 사람이 요리를 하고 장보고라는 사람이 홍길동에게 요리를 요청했다고 하자

  • 홍길동 -> 요리
  • 장보고 -> 요리 요청 -> 홍길동

그런데 이때, 홍길동이 퇴사를 했다고 하고 임꺽정이라는 사람이 이제 요리를 한다고 하자.

이 상황에서 장보고가 바라보고 있는 사람은 홍길동인데 갑자기 임꺽정을 바라봐야 하므로 코드가 꼬인다.

  • 홍길동 -> 요리(퇴사)
  • 임꺽정 -> 요리
  • 장보고 -> 요리 요청 -> 홍길동(X)

그래서, 애초에 프로그램을 만들 때 요리사라는 추상적인 class를 만들고 이를 상속받은 홍길동을 만든다.

또한, 종업원을 하나 만들고 종업원을 상속받은 장보고를 만든다.

  • 요리사 <- (상속) 홍길동
  • 종업원 <- (상속) 장보고

그리고 실제 호출시 장보고요리를 호출할 때 요리사를 호출함으로 요리사에 의존하게 만든다.

이렇게 하면 새로운 임꺽정이 나오더라도 원래 장보고가 바라보던 것은 요리사이므로 깔끔하게 프로그램을 업데이트 할 수 있다.

  • 요리사 <- 요리 <- 장보고
  • 요리사 <- (상속) 홍길동
  • 요리사 <- (상속) 임꺽정

즉, 의존성 역전 원칙을 정리하자면 구체적인 것에 의존하지 않고 추상적인 것에 의존하는 원칙이다.

 

의존성 역전 원칙을 가장 잘 지킨 디자인 패턴전략 패턴이다.(다음 글에 다뤄본다)

 

4. L(LSP - Liskov Substitution Principle - 리스코프 치환 원칙)

 

이 원칙은 프로그램의 객체는 프로그램의 정확성을 깨뜨리지 않으면서 하위 타입의 인스턴스로 바꿀 수 있어야 한다는 원칙이다.

 

예로, 너비와 높이의 조회(getter) 및 할당(setter) 메서드를 가진 직사각형 클래스로부터 정사각형 클래스를 파생하는 경우를 들 수 있다.

  • 직사각형(Getter, Setter)
  • 직사각형 <- 정사각형(Getter, Setter)


정사각형 클래스는 항상 너비와 높이가 같다. 하지만,
정사각형 객체가 직사각형을 다루는 문맥에서 사용되는 경우,
정사각형의 크기는 독립적으로 변경할 수 없기 때문에 (혹은 그래서는 안되기 때문에) 예기치 못한 행동을 하게 된다.

  • Setter로 인한 문제 발생

정사각형 클래스의 할당 메서드를 수정하여 정사각형의 불변 조건(즉, 너비와 높이가 같음)을 유지하면,
이 메서드는 크기를 독립적으로 변경할 수 있다고 설명한 직사각형의 할당자의 사후 조건을 무력화(위반)한다.

여기서 중요한 사안은 가변성이다. 정사각형과 직사각형이 조회 메서드만 가진다면 (즉, 이들이 불변 객체라면)

LSP를 위반하지 않는다.

 

5. I(ISP - Interface Segregation Principle - 인터페이스 분리 원칙)

 

인터페이스 분리 원칙은 클라이언트가 자신이 이용하지 않는 메서드에 의존하지 않아야 한다는 원칙이다.


인터페이스 분리 원칙은 큰 덩어리의 인터페이스들을 구체적이고 작은 단위들로 분리시킴으로,

클라이언트들이 꼭 필요한 메서드들만 이용할 수 있게 한다.

인터페이스 분리 원칙을 통해 시스템의 내부 의존성을 약화시켜 리팩토링, 수정, 재배포를 쉽게 할 수 있다.

인터페이스 분리 원칙은 SOLID 5원칙의 하나이며, GRASP의 밀착 원칙과 비슷하다.

 

'Design Pattern' 카테고리의 다른 글

[Design Pattern] 탬플릿 메서드 패턴  (0) 2024.03.28
[Design Pattern] 싱글톤 패턴  (0) 2024.03.25
[Design Pattern] 어댑터 패턴  (0) 2024.03.18
[Design Pattern] 프록시 패턴  (1) 2024.03.12
[Design Pattern] 전략 패턴  (1) 2024.03.12