[클린 소프트웨어] chapter 11. 의존 관계 역전 원칙 (DIP), chapter 12. 인터페이스 분리 원칙 (ISP)

이다은·2023년 9월 7일
0

독서

목록 보기
6/8
post-thumbnail

💡 Chapter 11. 의존 관계 역전 원칙 (DIP)

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

의존 관계 역전 원칙(DIP)
상위 수준의 모듈이 하위 수준의 모듈에 의존해서는 안 된다. 둘 다 추상화에 의존해야 한다.
또한 추상화는 구체적인 사항에 의존해서는 안 된다. 구체적인 사항이 추상화에 의존해야 한다.

기존의 병폐

  • 상위 수준의 모듈이 하위 수준의 모듈에 의존하는 경우
    • 상위 수준의 모듈은 어플리케이션의 본질을 담고 있다.
    • 그러나 상위 모듈이 하위 모듈에 의존할 때, 하위 모듈 변경은 상위 모듈에 직접적인 영향을 미칠 수 있고, 나아가서 상위 수준 모듈이 변경되게 할 수도 있다.
    • 상위 모듈은 어떤 식으로든 하위 모듈에 의존해서는 안 된다.
  • 정책이 구체적인 것에 의존하는 경우
    • 정책을 결정하는 것은 상위 수준의 모듈이다.
    • 우리가 재사용하기를 원하는 것은 정책을 결정하는 상위 수준의 모듈이다.
    • 상위 수준의 모듈이 하위 수준의 모듈에 독립적이면, 재사용하기 쉽다.

역전(inversion)

잘 설계된 객체 지향 프로그램의 의존성 구조는 전통적인 절차적 방법에 의해 일반적으로 만들어진 의존성 구조가 역전 된 것이다.

레이어 나누기

잘 구조화된 모든 객체 지향 아키텍처는 레이어를 분명하게 정의했다. 여기서 각 레이어는 잘 정의되고 제어되는 인터페이스를 통해 일관된 서비스의 집합을 제공한다. - 부치(Booch) -

미숙한 레이어

역전된 레이어

그래서 역전은?

의존성의 방향을 역전시키고, 하위 수준 모듈이 상위 수준 모듈에 선언된 인터페이스에 의존하게 만드는 것
여기서 역전은 의존성 뿐만 아니라, 인터페이스 소유권 에 대한 것도 의미한다.

헐리우드(Hollywood) 원칙이란?

  • 하위 수준 모듈에서 시스템에 접속을 할 수는 있지만, 어떤 식으로 그 모듈을 사용할지는 상위 수준 모듈에서 결정하게 된다.
  • 즉, 상위 수준 모듈에서 하위 수준 모듈에 먼저 연락하지 마세요. 저희(상위 수준 모듈)가 먼저 연락 드리겠습니다. 라고 말하는 원칙이다.
  • DIP와 관계가 깊다.

이렇게 의존성을 역전시킴으로써, 우리는 좀 더 유연하고, 튼튼하고, 이동이 쉬운 구조를 만들 수 있다.

추상화에 의존하자

구체 클래스(concrete class)에 의존해서는 안 되고, 프로그램의 모든 관계는 어떤 추상 클래스나 인터페이스에 맺어져야 한다.

고지식한 원칙

  • 어떤 변수도 구체 클래스에 대한 포인터나 참조값을 가져서 안 된다.
  • 어떤 클래스도 구체 클래스에서 파생(상속)되어서는 안 된다.
  • 어떤 메소드도 그 기반 클래스에서 구현된 메소드를 오버라이드해서는 안 된다
    : LSP포함

구체 클래스가 너무 많이 변경 되지 않으면서, 다른 비슷한 파생 클래스가 만들어지지 않는다면 이것에 의존하는 것은 그리 큰 해가 되지 않는다

→ 휘발적인 클래스에는 직접적으로 의존하지 않아야 한다.

너무 고지식할 필요까진 없다.

→ 상황에 따라서 고지식할 때도 있고, 유연하게 넘겨야할 때도 있다.

결론

  • 전통적인 절차 지향 방식은 정책이 구체적인 것에 의존하는 의존성 구조를 만든다. 이 경우 정책이 구체적인 것의 변경에 따라 같이 변한다.
  • 객체 지향 프로그래밍은 이것을 역전 시켜서 구체적인 것과 정책이 모두 추상화에 의존하게 한다.
  • 프로그램의 의존성이 역전되어 있다면 이것은 객체 지향 설계이며, 의존성이 역전되어 있지 않다면 절차적 설계이다.
  • 의존성 역전을 사용하면 프레임워크가 재사용 가능해지고, 변경에 탄력적이며, 추상화와 구체적 사항이 서로 분리되어 있기 때문에, 이 코드는 유지보수하기가 훨씬 쉽다.

💡 Chapter 12. 인터페이스 분리 원칙 (ISP)

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

  • ISP는 ‘비대한’ 인터페이스의 단점을 해결한다.
  • 비대한 인터페이스는 응집력이 없는 인터페이스이다.

인터페이스 오염

  • 클라이언트가 사용하지 않는 인터페이스가 구현되어 있는 경우
  • 일부 구상체에 불필요한 인터페이스가 구현되어 있는 경우
  • 파생 클래스가 새로운 메소드를 필요로 할 때마다 그 메소드가 기반 클래스에도 포함되어야 한다. 이것은 기반 클래스의 인터페이스를 ‘비대하게’ 만든다
    불필요한 복잡성 과 불필요한 중복성

클라이언트가 인터페이스에 미치는 반대 작용

  1. 클라이언트의 요구사항 변경으로 인해 인터페이스가 변경되는 경우가 자주 생긴다.
  2. 이 상황에서 해당 인터페이스가 비대해서 여러 구상체를 지니고 있으면, 요구사항 변경으로 인한 영향 범위가 넓다.
  3. 그로 인해서 비용과 부작용의 위험성이 급격하게 증가한다.

인터페이스 분리 원칙(ISP)
클라이언트가 자신이 사용하지 않는 메소드에 의존하도록 되어서는 안 된다.

어떤 클라이언트(A)가 자신은 사용하지 않지만 다른 클라이언트(B)가 사용하는 메소드를 포함하는 클래스에 의존할 때, 그 클라이언트(A)는 다른 클라이언트(B)가 그 클래스에 가하는 변경에 영향을 받게 된다. 
우리는 가능하다면 이런 결합을 막고 싶다. 따라서 인터페이스를 분리 하기를 원한다.

다중 상속을 통한 분리

위 구조처럼 다중 상속을 통해 인터페이스를 분리할 경우, 기반 클래스들은 분리된 인터페이스를 통해 같은 객체를 사용하게 된다. 이는 다른 클라이언트의 변경에 의한 영향을 피할 수 있다.

복합체와 단일체

만약 인터페이스 복수 개(복합체)와 클래스 1개(단일체) 중 선택해야 할 경우에는 인터페이스 복수 개(복합체)인 방식으로 구현하라.

결론

  • 비대한 클래스는 클라이언트간의 높은 결합도를 유발한다.
  • 클라이언트는 자신이 사용하는 메소드에만 의존해야 하는데, 비대한 클래스에 변경을 가하면 모든 나머지 클래스가 영향을 받게 된다
    클라이언트 고유의(client-specific) 인터페이스 여러 개로 분해해야 한다.
    → 이렇게 하면 호출하지 않는 메소드에 대한 클라이언트의 의존성을 끊고, 클라이언트가 서로에 대해 독립적이 되게 만들 수 있다

0개의 댓글