Skip to main content

부록 A. 계약에 의한 설계

  • 인터페이스만으로는 객체의 행동에 관한 다양한 관점을 전달하기 어렵습니다.
  • 명령의 부수효과를 쉽고 명확하게 표현할 수 있는 커뮤니케이션 수단이 필요하며, 이때 계약에 의한 설계(Design By Contract, DBC) 가 주는 혜택을 보게 됩니다.

01. 협력과 계약#

부수효과를 명시적으로#

  • 계약에 의한 설계를 사용하면 제약 조건을 명시적으로 표현하고 자동으로 문서화할 수 있을뿐만 아니라 실행을 통해 검증할 수 있습니다.

계약#

  • 계약에 대한 세부조건은 아래와 같은 특성을 가집니다.
    • 각 계약 당사자는 계약으로부터 이익(benefit) 을 기대하고 이익을 얻기 위해 의무(obligation) 을 이행합니다.
    • 각 계약 당사자의 이익과 의무는 계약서에 문서화됩니다.
  • 계약은 협력을 명확하게 정의하고 커뮤니케이션할 수 있는 범용적인 아이디어입니다.

02. 계약에 의한 설계#

  • 계약은 협력에 참여하는 두 객체의 사이의 의무와 이익을 문서화한 것 입니다.
    • 각 계약 당사자는 계약으로부터 이익(benefit) 을 기대하고 이익을 얻기 위해 의무(obligation) 을 이행합니다.
    • 각 계약 당사자의 이익과 의무는 계약서에 문서화됩니다.
  • 계약에 의한 설계 개념은 "인터페이스에 대해 프로그래밍하라"는 원칙을 확장한 것입니다.
  • 일반적으로 세 가지 기대가 바로 계약에 의한 설계를 구성하는 세 가지 요소에 대응됩니다.
    • 사전조건(precondition) : 메서드가 호출되기 위해 만족돼야 하는 조건
    • 사후조건(postcondition) : 메서드가 실행된 후에 클라이언트에게 보장해야 하는 조건
    • 불변식(invariant) : 항상 참이라고 보장되는 서버의 조건

사전조건#

  • 사전조건을 만족시키지 못해서 메서드가 실행되지 않을 경우 클라이언트에 버그가 있다는 것을 의미합니다.
  • 일반적으로 사전조건은 메서드에 전달된 인자의 정합성을 체크하기 위해 사용됩니다.

사후조건#

  • 일반적으로 사후조건은 다음의 세 가지 용도로 사용됩니다.
    • 인스턴스 변수의 상태가 올바른지를 서술하기 위해
    • 메서드에 전달된 파라미터의 값이 올바르게 변경됐는지를 서술하기 위해
    • 반환값이 올바른지를 서술하기 위해
  • 아래의 두 가지 이유로 인해 사전조건보다 어려울 수 있습니다.
    • 한 메서드 안에서 return 문이 여러 번 나올 경우
    • 실행 전과 실행 후의 값이 비교해야 하는 경우

불변식#

  • 불변식은 다음과 같은 두가지 특성을 가집니다.
    • 불변식은 클래스의 모든 인스턴스가 생성된 후에 만족돼야 합니다.
    • 불변식은 클라이언트에 의해 호출 가능한 모든 메서드에 의해 준수돼야 합니다.

03. 계약에 의한 설계와 서브타이핑#

  • 서브타입이 리스코프 치환 원칙을 만족시키기 위해서는 클라이언트와 슈퍼타입 간에 체결된 계약을 준수해야 합니다.
  • 리스코프 치환 원칙의 규칙을 두 가지 종류로 세분화할 수 있습니다.
    • 첫 번째 규칙은 협력에 참여하는 객체에 대한 기대를 표현하는 계약 규칙
    • 두 번째 규칙은 교체 가능한 타입과 관련된 가변성 규칙
  • 계약 규칙(contract rules)은 슈퍼타입과 서브타입 사이의 사전조건, 사후조건, 불변식에 대한 서술할 수 있는 제약에 관한 규칙
    • 서브타입에 더 강력한 사전조건을 정의할 수 없습니다.
    • 서브타입에 더 완화된 사후조건을 정의할 수 없습니다.
    • 슈퍼타입의 불변식은 서브타입에서도 반드시 유지돼야 합니다.
  • 가변성 규칙(varinace rules) 은 파라미터와 리턴 타입의 변형과 관련된 규칙입니다.
    • 서브타입의 메서드 파라미터는 반공변성을 가져야 합니다.
    • 서브타입의 리턴 타입은 공변성을 가져야 합니다.
    • 서브타입은 슈퍼타입이 발생시키는 예외와 다른 타입의 예외를 발생시켜서는 안됩니다.

계약 규칙#

  • 서브타입에 더 강력한 사전조건을 정의할 수 없습니다.
    • 사전조건을 보장해야 하는 책임은 클라이언트에게 있습니다.
  • 서브타입에 더 완화된 사후조건을 정의할 수 없습니다.
    • 사후조건 완화는 리스코프 치환 원칙 위반입니다.
    • 사후조건 강화는 계약에 영향을 미치지 않습니다.
    • 일찍 실패하기 > 문제가 발생한 곳에서 프로그램이 실패하도록 만드는 것이 좋습니다.
  • 슈퍼타입의 불변식은 서브타입에서도 반드시 유지돼야 합니다.
    • 계약 관점에서 캡슐화는 중요합니다. (변경 측면에서)

가변성 규칙#

  • 서브타입은 슈퍼타입이 발생시키는 예외와 다른 타입의 예외를 발생시켜서는 안됩니다.
    • 클라이언트의 관점에서 자식클래스가 부모 클래스가 하는 일보다 더 적은 일을 수행한다는 공통점이 있습니다.
  • 서브타입의 리턴 타입은 공변성을 가져야 합니다.
    • 공변성에 대한 정의
      • 공변성 : S와 T 사이의 서브타입 관계가 그대로 유지됩니다.
      • 반공변성 : S와 T 사이의 서브타입 관계가 역전됩니다.
      • 무공변성 : S와 T 사이에는 아무런 관계도 존재하지 않습니다.
    • 부모 클래스에서 구현된 메서드를 자식 클래스에서 오버라이딩할 때 부모 클래스에서 선언한 반환타입의 서브타입으로 지정할 수 있는 특성을 리턴 타입 공변성(return type convariance) 라고 부릅니다.
  • 서브타입의 메서드 파라미터는 반공변성을 가져야 합니다.
    • 부모 클래스에서 구현된 메서드를 자식 클래스에서 오버라이딩할 때 파라미터 타입을 부모 클래스에서 사용한 파라미터의 슈퍼타입으로 지정할 수 있는 특성을 파라미터 타입 반공변성(parameter type contravariance) 라고 부릅니다.

함수 타입과 서브타이핑#

  • 최근의 객체지향 언어들은 이름 없는 메서드를 정의할 수 있게 허용합니다.
    • 익명함수, 함수 리터럴, 람다 표현식 등.
Last updated on