SOLID 객체지향 설계 원칙

  1. SRP: 단일 책임 원칙
  2. OCP: 개방-폐쇄 원칙
  3. LSP: 리스코프 치환 원칙
  4. ISP: 인터페이스 분리 원칙
  5. DIP: 의존성 역전 원칙

Single Responsibility Principle

단일 클래스는 단 한 개의 책임을 가져야 한다. (= 클래스를 변경하는 이유는 오직 하나여야만 한다)

하나의 클래스가 여러 개의 변경하는 메소드를 갖고 있다면, 이 클래스를 분리하라는 신호일 수 있다. 그런데 정확히 ‘변경하다’의 의미가 무슨 뜻일까?

Open-Closed Principle

객체는 확장에 대해서는 열려있지만, 수정에 대해서는 닫혀있다.

상속(Inheritance) 또는 합성(Composition)을 통해 기능을 확장할 수 있다. 요구사항이 변경되었을 때, 기존 클래스 메소드의 내부 코드를 변경하는 대신, 새로운 클래스나 기능을 만들어서 확장하는 것이 이상적이다.

Liskov Substitution Principle

자식 클래스(하위 타입)은 부모 클래스를 항상 대체할 수 있다.

자식 클래스 S의 개체는 모두 부모 클래스 T의 개체라고 간주할 수 있어야 한다. 즉 is-a 관계가 성립해야 한다.

Interface Segregation Principle

인터페이스는 그 인터페이스를 사용하는 클라이언트를 기준으로 분리한다.

클라이언트에서 사용하지 않는 메소드가 존재하면 안 된다. 그러므로 하나의 인터페이스를 여러 개의 클라이언트가 불필요한 메소드를 구현하면서까지 공유하는 것보다, 인터페이스 자체를 분리하는 것이 옳다.

Dependency Inversion Principle

고수준 모듈은 저수준 모듈의 구현에 의존해서는 안 된다. (= 저수준 모듈이 고수준 모듈에서 정의한 추상 타입에 의존해야 한다.)

  • 고수준 모듈: 의미있는 단일 기능을 제공하는 모듈
    • ex) 바이트 데이터를 읽어온다 → 암호화하고 → 결과 바이트 데이터를 쓴다
  • 저수준 모듈: 고수준 모듈의 기능을 구현하기 위해 필요한 개별 기능
    • ex) 파일에서 바이트 데이터를 읽어온다 → AES 알고리즘으로 암호화 → 파일에 바이트 데이터를 쓴다

추가: 디미터(Demeter) 법칙

어떤 객체의 메소드는 다음과 같은 종류의 객체에 있는 메소드들만 실행시킬 수 있다.

  1. 객체의 메소드
  2. 메소드의 변수
  3. 메소드 안에서 만들어진 객체
  4. 객체가 직접 관리하는 component 객체
  5. 메소드의 스코프 안에서 객체가 접근 가능한 전역변수

즉, 어떤 객체의 메소드에서 다른 객체에 속한 변수에 직접 접근하는 것은 잘못된 설계의 신호일 수 있다.

예시

어떤 원칙이 깨질 때에 어떤 현상이 나타나는지 그 예시를 아래의 글에서 확인할 수 있다.

  • https://jungwoon.github.io/solid/2017/07/31/Solid-Principle/

객체지향 3요소

  1. Encapsulation
  2. Inheritance or Delegation
  3. Polymorphism