해당 자료는 부산대학교 채흥석 교수님의 소프트웨어 공학 강의 자료입니다.

예전에 블로그에서 객체 지향에 대해서 얘기할 때, SOLID에 대해 배웠었다.
이번에는 객체 지향의 5원칙인 SOLID에 대해 더 자세하게 알아보도록 하자.

What is SOLID?

앞서 배운 설계의 원칙들에 이어서, 좀 더 세분화 된 원칙이다.
객체 지향 프로그래밍에 있어서 지켜야할 5가지 대원칙이다.

SRP

SRP(Single Responsibility Principle)이란, 직역하면 단일 책임 원칙이다.

Responsibility is axis of change, Robert Martin.

SRP가 내포하는 의미는 아래와 같다.

  • Class, Function 등의 하나의 모듈은 반드시 책임을 하나만 가져야 한다.
    올바른 단일책임
    • 책임이란, 같은 이유로 동시에 변경이 일어나는 코드의 집합을 의마한다.
    • 즉, 모듈을 변경하는 데에는 반드시 한 가지의 이유만 존재해야 한다.
  • Bad smells
    • Divergent Change : 하나의 Class가 다양한 이유로 다양하게 변경되는 악취.
    • Shotgun Surgery : 하나의 변경이 여러 Class의 변경으로 이어지는 악취.
  • Functional Example
    srp
    • 위의 코드를 예시로 생각해보자.
    • printf 문의 출력 순서가 바뀔 수가 있다.
      • 화면에 출력하는 것이 아닌 출력 방식을 바꿀 수가 있다.
    • 비디오를 빌리는 charge를 줄일 수가 있다.
      • 어? 이 순간 Responsibility는 2개가 되어 SRP 위반이 된다!
    • point를 더 올려줄 수가 있다.
      • 이젠 Responsibility가 3개가 됐다.
      • 위의 3가지는 굳이 같이 변경이 일어날 필요가 없다. 따라서 SRP를 위반한다!
    • 이를 해결하기 위해, 모두 함수로 Extract 시켜 각각의 함수에 책임을 부여하도록 할 수 있다!
      • 함수의 갯수는 늘어나지만, Refactoring 을 통해 함수의 크기는 줄어든다!
    • 이전에 학습했던 Logical Cohesion 또한 SRP 위반에 해당한다.

OCP

OCP(Open-Closed Principle)이란, 직역하면 개방 폐쇄 원칙이다.

Software Entities should be open for extension, but closed for modification, Bertrand Meyer.

위의 말 그대로, 확장에는 열려있으나 변경에는 닫혀있어야 한다는 원칙이다.

  • Example : getSum() 함수

LSP

LSP(Liskov Substitute Principle)이란, 직역하면 리스코프 치환 원칙이다.
이는 상속 관계에서, Super Class는 Sub Class의 존재에 대해 알 필요가 없다는 원칙이다.

LSP에 대한 위반은 곧 OCP의 위반으로 이어질 수 있다!

ISP

ISP(Interface Segregation Principle)이란, 직역하면 인터페이스 분리 원칙이다.
인터페이스에 Method가 너무 많아, 너무 커져버리면 어떤 문제가 발생할까?

  • 하나의 Interface인데 Client마다 이용하는 Method가 상이해진다.
    • 자기가 쓰지도 않는 Method에 변경이 일어나 영향을 받을 수가 있다.
    • 이를 Fat interface(Polluted-interface, non-cohesive interface)라고 한다.

그럼 그냥 최소한의 기능만을 담고있는 Interface로 분할을 하자!

  • Example : 복합기

DIP

DIP(Dependency Inversion Principle)이란, 직역하면 의존관계 역전 원칙이다.
의존관계에 의해서 모듈들이 상호 의존을 하는 경우, 아래와 같은 문제가 발생할 수 있다.

  • Rigidity
    • 수정(변경) 하기가 쉽지가 않다.
    • 하나를 변경하면 연관된 많은 시스템들에 모두 영향을 미치기 때문이다.
  • Fragility
    • 파급 효과(Ripple effect)에 의해 변경했을 때 예기치 못한 오류가 발생할 수 있다.
  • Immobility
    • 특정 부분이 다른 코드와의 의존성이 높아, 재사용하기가 쉽지 않다.

위의 문제를 해결하기 위해서, 의존 관계의 역전을 이용한다.
원래는 상위 Class가 하위 구현체를 의존하는 형식을 사용할 수 있지만,
상위 Class가 Interface를 의존하도록 하며, 하위 Class들이 Interface를 의존하도록 한다.

그렇게 하면, 함수는 Interface만 의존해 구현을 하면 되는 것이며
실제로 사용할 때에 내가 원하는 구현체를 부품만 갈아 끼우듯 사용할 수 있는 것이다.

  • Example : Copy() 함수