본문 바로가기
Cloud/AWS

13장 서브클래싱과 서브타이핑

by 민휘 2024. 2. 1.

13장 읽고 나눈 이야기

  • 상속과 합성의 차이를 여기서 많이 이해한 듯. 합성은 확실히 퍼블릭 인터페이스를 공유하니까 더 유연하다.
  • 상속 대신 처음에는 인터페이스로 협력을 구축하고, 겹치는게 많으면 이전 장에서 봤던 것처럼 공통 구현을 가진 추상 클래스로 올리는 게 합리적이라고 생각함. Collection에서 ArrayList를 사용하더라도 선언은 List로 사용하는 편이 좋다.
  • 정말 변동 가능성이 크고 유연한 설계가 필요한 부분에만 서브타이핑을 적용하는게 좋다고 생각한다.

 

타입계층 구현의 핵심

  • 타입 : 적용 가능한 오퍼레이션 종류와 의미
  • 타입의 사용 효과 : 코드의 의미를 명확하게 전달, 개발자의 실수 방지
  • 객체의 타입 정의 : 수신 가능한 메시지를 정의
  • 서브타입이 슈퍼타입에 속할 수 있는 이유는 행동이 포함되기 때문

 

상속의 올바른 사용

  • 서브클래싱 : 코드의 재사용. 강한 결합으로 인해 코드 품질이 낮아진다.
  • 서브타이핑 : 타입 계층을 구현해 다형적인 객체 협력을 만든다. 복잡하지만 유연한 구조를 가진다.

 

타입 계층의 올바른 사용 조건

  • is a 구조를 가지며, 클라이언트 입장에서 부모와 자식의 행동이 호환된다.
  • 이때 자연어에 현혹되지 말고 시스템의 요구사항에 따라 행동 호환성을 판단할 것.
  • 예를 들어 새는 펭귄이다는 is a 관계를 만족하는 것처럼 보이는데, 클라이언트가 새는 날 수 있다는 행동을 기대한다면 새는 행동 호환성을 가지지 않는다.

 

인터페이스 분리하기 ISP

  • 클라이언트마다 기대하는 행동이 다르다. 이 행동을 담당하는 인터페이스를 작게 분리해 변경에 의한 영향을 각 인터페이스로 제한할 수 있다.
  • 이때 서브 타입 사이에 코드 재사용이 필요하다면, 상속보다는 합성을 사용해 퍼블릭 인터페이스만 재사용하는 것이 더 유연하다.

 

리스코프 치환 원칙 LSP

  • 상속 관계로 연결한 두 클래스가 서브타이핑 관계를 만족시키기 위해서는 LSP를 만족해야 한다.
  • 자식 클래스가 부모 클래스를 대체하기 위해서는 부모에 대한 클라이언트의 기대를 자식이 만족해야 한다. 직사각형과 정사각형은 언뜻 서브타입 관계처럼 보이지만, resize 관점에서 둘은 다르게 동작하므로 서브타입이 아니다.
  • LSP는 유연한 설계의 기반이다. 자식 클래스가 부모 클래스를 대체할 수 있다면 기능 확장을 위해 자식을 추가하더라도 코드를 수정할 필요가 없다.
  • 이때 핵심은 클라이언트 입장에서 부모 클래스에 바라는 행동이다.

 

클라이언트 입장에서의 대체 가능성

  • 계약에 의한 설계 개념을 포함함
  • 사전 조건(클라이언트 책임), 사후 조건(서버 책임), 클래스 불변식을 준수해야함
  • 자식 클래스가 부모 클래스보다 더 강한 사전 조건, 더 약한 사후 조건을 제시한다면 LSP를 위반해 클라이언트의 가정을 만족하지 못한다.