[스프링 입문을 위한 자바 객체 지향의 원리와 이해] 05. 객체 지향 설계 5원칙 - SOLID

off_sujin·2022년 6월 14일
0

🌵 SOLID

SOLID는 로버트 C. 마틴이 객체 지향 프로그래밍 및 설계의 다섯 가지 기본 원칙으로 제시한 것이다.

  • SRP : 단일 책임 원칙
  • OCP : 개방 폐쇄 원칙
  • LSP : 리스코프 치환 원칙
  • ISP : 인터페이스 분리 원칙
  • DIP : 의존 역전 원칙

이 원칙들은 다음의 고전 원칙을 객체 지향의 관점에서 재정립한 것이다.

High Cohesion, Loose Coupling
응집도는 높이고, 결합도는 낮춰라

🌱 결합도와 응집도

결합도(Cohesion)

  • 모듈 간의 상호 의존 정도
  • 결합도가 낮으면 모듈 간의 상호 의존성이 줄어들어 객체의 재사용이나 수정, 유지보수가 용이하다.

응집도(Coupling)

  • 하나의 모듈 내부에 존재하는 구성 요소들의 기능적 관련성
  • 응집도가 높은 모듈은 하나의 책임에 집중하고 독립성이 높아져 객체의 재사용이나 기능의 수정, 유지보수가 용이하다.

이제 각각의 원칙들을 알아보자.

🌵 SRP(Single Responsibility Principle) - 단일 책임 원칙

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

역할과 책임에 따라 분리하라.

만약 음식점이라는 한 클래스에서 요리도 하고, 주문도 받고, 배달도 한다면 유지보수하기에 아주 어지러울 것이다.

class 음식점 {
	void 요리하기() {
    	// 맛있게 만들어준다.
    }
    
    void 주문받기() {
    	// 손님에게 친절하게 대응하며 주문을 받는다.
    }
    
    void 배달하기() {
    	// 빠르고 안전한 배달 서비스합니다.
    }
}

이를 SRP를 적용하면 아래의 코드처럼 각각의 역할을 만들어서 분리시키면 된다.

class 요리사 {
	void 요리하기() {
    	// 맛있게 만들어준다.
    }
}

class 캐셔 {
    void 주문받기() {
    	// 손님에게 친절하게 대응하며 주문을 받는다.
    }
}

class 배달원 {
    void 배달하기() {
    	// 빠르고 안전한 배달 서비스합니다.
    }
}

단일 책임의 원칙은 클래스 뿐만 아니라 속성, 메서드, 패키지, 모듈, 컴포넌트, 프레임워크 등에도 적용할 수 있다.

🌵 OCP(Open/Closed Principle) - 개방 폐쇄 원칙

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

자신의 확장에는 열려있고, 주변의 변화에는 닫혀있어야 한다.

🌵 LSP(Liskov’s Substitution Principle) - 리스코프 치환 원칙

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

상위 클래스의 객체 참조 변수에는 하위 클래스의 인스턴스를 할당할 수 있어야한다.

객체 지향에서의 상속은 조직도나 계층도가 아닌 분류도가 돼야 한다.

리스코프 치환 원칙은 객체 지향의 상속이라는 특성을 올바르게 활용하면 자연스럽게 얻게 되는 것이다.

하위 클래스 is a kind of 상위 클래스 - 하위 분류는 상위 분류의 한 종류다.
구현 클래스 is able to 인터페이스 - 구현 분류는 인터페이스할 수 있어야 한다.

리스코프 치환 원칙 위키

하위형에서 선행 조건은 강화될 수 없다.
하위형에서 후행 조건은 약화될 수 없다.
하위형에서 상위형의 불변 조건은 반드시 유지돼야 한다.

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

"클라이언트는 자신이 사용하지 않는 메서드에 의존 관계를 맺으면 안 된다." - 로버트 C.마틴

비대한 인터페이스를 각 클라이언트에 특화되도록 분리시켜라.

인터페이스 최소주의 원칙

인터페이스를 통해 메서드를 외부에 제공할 때 최소한의 기능만 제공해야한다.

🌵 DIP(Dependency Inversion Principle) - 의존 역전 원칙

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

자신보다 변하기 쉬운 것에 의존하지 마라.

JPA에서 DIP의 예를 볼 수 있다.

  • JPA가 구체적인 데이터베이스(MySQL, H2...)이 아닌 추상화된 Dialect에만 의존하게 한다.
  • 이로써 데이터베이스가 변경되어도 JPA는 그 영향을 받지 않는다.
  • OCP와 유사하다!

즉, DIP는 자신보다 변하기 쉬운 것에 의존하던 것을 추상화된 인터페이스나 상위 클래스를 두어 변하기 쉬운 것의 변화에 영향받지 않게 하는 것이다.

상위클래스일수록, 인터페이스일수록, 추상 클래스일수록 변하지 않을 가능성이 높다.
따라서 하위 클래스나 구체 클래스가 아닌 상위클래스, 인터페이스, 추상 클래스를 통해 의존하는 것이 DIP이다.

🌵 정리 - 객체 지향 세계와 SOLID

SOLID 원칙을 적용하면 소스 파일의 개수가 더 많아지는 경향이 있다.

하지만 이는 이해하기 쉽고, 유지보수가 편하도록 만든 것이기 때문에 충분히 감수할 만하다.

SoC(Separation Of Concerns)

  • 관심사가 같은 것끼리는 하나의 객체 또는 친한 객체로 모은다.
  • 관심사가 다른 것은 가능한 한 따로 떨어져 서로 영향을 주지 않도록 분리한다.
  • 하나의 속성, 메소드, 클래스, 모듈, 패키지에는 하나의 관심사만 들어있어야 한다.

SoC를 적용하면 SRP, ISP, OCP에 자연스럽게 도달할 수 있다.

profile
학습 중..

0개의 댓글