객체지향 개발 5대 원칙 SOLID

모든 문제의 원인은 어플리케이션의 기능 수정, 추가에 있다.
기존의 코드가 기능 수정, 추가를 예상하지 않고 개발하게 되면
개발 비용이 많이 발생하고 예상하지 못한 에러나 예외를 발생시킨다.

복잡한 논리일 수록 이런 문제가 자주 발생한다.
기능 수정, 추가가 쉬운 복잡한 논리의 어플리케이션을 개발하기 위해 객체지향 개발이 만들어졌다.
그리고 더 수월하고 명확하게 추상적인 객체지향 개발을 하기 위해 SOLID 라는 5가지 원칙이 만들어졌다.


1. SOP(Single Resposibility Principle)

  • 객체는 한 가지의 변경 이유만 가져야 한다. → 응집도가 높아야 한다.
  • 응집도 : 객체에 얼마나 관련있는 책임을 할당했는가?
  • 응집도가 높은 객체일 수록 좋은 객체이다.
    예를 들어 도메인 객체를 레포지토리에 저장하기 위한 로직을 도메인 객체에 넣지 않고 DAO 로 분리하고
    데이터 전송을 위한 로직(직렬화, 역직렬화 등)을 도메인 객체에서 분리해 DTO 로 분리하는 경우가 있다.

2. OCP (Open-Close Principle)

  • 기능 추가에는 개방되어 있고, 코드 수정에는 닫혀 있어야 한다. → 기존 코드를 수정하지 않고 어플리케이션의 기능을 확장, 수정할 수 있다.
  • 추상화에 의존하도록 개발하면 OCP 를 지킬 수 있다.
  • 기존 절차적 프로그래밍은 동작이 구체적인 구현(프로시저)에 의존한다.
  • 객체지향 프로그래밍은 구현을 인터페이스로 캡슐화 한 추상화된 객체에 의존하도록 한다.
  • 컴파일 타임 의존성과 런타임 의존성이 다르게 된다.
  • 어플리케이션의 구체적인 실행이 런타임에 결정되므로 기능 추가와 수정에 유연하게 된다.

3. LCP (Liskov Substitution Principles)

  • 서브 타입은 그것의 기반 타입에 대체 가능해야 한다.
    → 상속에 관련된 내용이다. 클라이언트가 부모 타입으로 자식 타입을 사용할 수 있어야 한다.
  • 클라이언트 입장에서 부모 타입의 행동과 자식 타입의 행동에 호환성이 있어야 한다.
    → 부모 클래스로 자식 클래스를 받았을 때, 부모 클래스의 메소드로 자식 클래스에서 제공하는 기능(구현)을 사용할 수 있어야 한다.
  • 서브 클래싱 : 부모 클래스의 코드를 재사용하기 위해 상속을 사용
  • 서브 타이핑 : 타입 계층을 구성하기 위해 상속을 사용
    → 클라이언트 관점에서 IS-A 관계를 가지고, 행동호환성이 있어야 한다.
  • 다른 클래스의 코드를 재사용할 목적인 경우 상속 대신 합성을 사용해야 한다.

4. ISP (Interface Segregation Principle)

  • 사용하지 않는 인터페이스는 구현하지 말아야 한다.
    → 일반적인 인터페이스 하나 보다 구체적인 인터페이스 여럿이 더 낫다.
  • 인터페이스를 클라이언트의 기대에 따라 나눈다.
    FT_2021-08-26 12_56_21 201

5. DIP (Dependency Inversion Principle)

  • 고수준 요소에서 저수준 요소에 의존하게 만들어 의존성을 최대한 느슨하게 만든다.
  • 결합도 : 의존성의 정도. 의존성을 따라서 요소의 변경, 수정의 영향을 받는다. 의존성이 느슨할 수록 의존된 객체의 변경에 따른 수정의 영향을 덜 받게 된다.
  • DIP 를 지키면 자연스럽게 IoC (Inversion of Control) 도 지켜진다.
  • 고수준 요소에서 저수준 요소가 언제, 어떻게 사용할 지 결정한다.
    → 프레임워크(고수준) 에서 어플리케이션의 서브클래스(저수준)을 호출해 제어 흐름의 주체가 프레임워크로 이동한다.
    → 알고리즘을 캡슐화 하는 템플릿 메소드 패턴, 고수준 요소가 저수준 요소를 호출해 의존성 부패를 해결하는 헐리우드 원칙을 활용해 IOC 를 달성할 수 있다.