오브젝트 - 부록 A 계약에 의한 설계

yshjft·2023년 12월 13일
0

오브젝트

목록 보기
16/18

1 협력과 계약

부수효과를 명시적으로

  • 계약에 의한 설계 라이브러리(Code Contracts)를 이용하여 메서드의 순서와 관련된 제약을 명확하게 표현할 수 있다.

계약

  • 한쪽의 의무가 반대쪽의 권리가 된다
  • 계약의 내용을 위반한다면 계약은 정상적으로 완료되지 않는다.

2 계약에 의한 설계

  • 협력에 참여하는 각 객체는 계약으로부터 이익을 기대하고 이익을 얻기 위해 의무를 이행한다.
  • 협력에 참여하는 객체의 이익과 의무는 객체의 인터페이스 상에 문서화된다.
  • 계약에 의한 설계 개념
    • '인터페이스에 의해 프로그래밍하라'는 원칙을 확장한 것
  • 의도를 드러내는 인터페이스
    • 오퍼레이션의 시그니처만으로도 클라이언트와 서버가 협력을 위해 수행해야 하는 제약조건을 명시할 수 있다.
  • 계약에 의한 설계를 구성하는 세 가지 요소
    • 사전조건: 메서드가 호출되기 위해 만족돼야 하는 조건
    • 사후조건: 메서드가 실행된 후에 클라이언트에게 보장해야 하는 조건
    • 불변식: 항상 참이라고 보장되는 서버의 조건. 메서드를 실행하기 전이나 종료된 후나 불변식은 항상 참이여야 한다.

사전조건

  • 메서드가 정상적으로 실행되기 위해 만족해야하는 조건
  • 사전조건을 만족시킬 책임은 메서드를 호출하는 클라이언트에게 있다.

사후조건

  • 결과가 올바른지 검사
  • 유효한 상태로 남아 있는지 검사

사후조건의 용도

  • 인스턴스 변수의 상태가 올바른지를 서술하기 위해
  • 메서드에 전달된 파라미터의 값이 올바르게 변경됐는지 서술하기 위해
  • 반환값이 올바른지 서술하기 위해

사후조건 정의가 어려운 이유

  • 메서드에 return 문이 여러번 나오는 경우 모든 return 보다 결과값이 올바른지 검증하는 코드를 추가해야 한다.
  • 실행 전과 실행 후의 값을 비교해야 하는 경우

불변식

  • 내부 상태(필드)와 관련됨
  • 클래스에 정의된 모든 생성자는 불변식을 준수해야 한다.
  • 클라이언트에 의해 호출 가능한 모든 메서드에 의해 준수돼야 한다. 메서드 실행 전과 메서드 종료 후에는 항상 불변식을 만족하는 상태가 유지돼야 한다.

3 계약에 의한 설계와 서브타이핑

  • 사전조건: 클라이언트가 만족시켜야 하는 조건
  • 사후조건: 서버가 만족시켜야 하는 조건

계약 규칙

  • 서브타입인지 확인하기 위해서는 리스코프 치환 원칙을 만족하는지 살펴봐야 한다.
  • 서브타입이 되기 위해서는 위에서 정의한 사전조건과 사후조건을 만족해야 한다.

서브타입에 더 강력한 사전조건을 정의할 수 없다.

  • 사전조건을 만족시키는 것은 클라이언트의 책임
  • 만약 서브타입이 슈퍼타입에 정의된 사전조건을 강화하면 클라이언트가 슈퍼타입의 기준에 의해 맞춘 사전조건은 무의미해진다.
    • 이는 계약을 위반한 것이며 서브타입은 슈퍼타입을 대체할 수 없게 된다.
    • 리스코프 치환 원칙 위반
  • 서브타입의 사전조건을 완화시키는 것은 클라이언트에게 어떠한 여향도 주지 않기 때문에 리스코프원칙을 위반하지 않습니다.

서브타입에 더 완화된 사후조건을 정의할 수 없다.

  • 사후조건 만족의 책임은 서버에게 있다.
  • 사후조건을 완화하는 것은 서버가 클라이언트에게 제공하겠다고 보장한 계약을 충족시켜주지 못한다
    • 따라서 서브타입의 사후조건 완화는 리스코프 치환 원칙 위반
  • 다만 사후조건 강화는 계약에 영향을 주지 않는다.

추가) 일찍 실패하기

  • 사후조건은 서버가 보장해야 한다
  • 문제가 발생하면 그 위치에서 프로그램이 실패하도록 만들어야 한다.
    • 문제가 발생할 경우 원이이 어디인지를 빠르게 알 수 있다.

불변식은 서브타입에서도 반드시 유지되어야 한다.

  • 메서드가 실행도기 전과 후 반드시 만족시켜야 하는 조건
  • 메서드를 실행하는 도중에는 만족시키지 않아도 된다.
  • protected 인스턴스 변수
    • protected 인스턴스 변수는 자식 클래스에 의해 쉽게 변경될 수 있다.
    • 이로 인해 부모클래스의 불변성은 쉽게 무너질 수 있다.
    • 따라서 protected 보다는 private을 사용하는 것이 조핟.
    • 자식 클래스에서 부모 클래스의 인스턴스 변수의 상태를 변경하고 싶다면 부모 클래스에서 protected 메서드를 제공해야 한다.

가변성 규칙

서브타입은 슈퍼타입이 발생시키는 예외와 다른 예외를 발생시켜서는 안된다.

  • 클라이언트에서 예상할 수 없는 예외를 던져서는 안된다.
  • 추가) 기능을 퇴화시켜서도 안된다.
  • 클라이언트의 관점에서 자식 클래스가 부모 클래스가 하는 일보다 더 적은 일을 수행하면 동일하게 취급할 수 없다.
    • 리스트코프 치환 원칙이 성립하지 않는다.

서브타입의 리턴 타입은 공변성을 가져야 한다.

  • ✳︎ S가 T의 서브타입
  • 공변성
    • S와 T 사이의 서브타입 관계가 그대로 유지
    • 리스코프 치환 원칙은 공변성과 관련된 원칙
  • 반공변성
    • 슈퍼타입인 T가 서브타입인 S 대신 사용될 수 있다.
  • 무공변성
    • S 대신 T를 사용하거나 T 대신 S르 사용할 수 없다.
  • 공변성과 반공변성의 영역으로 들어서기 위해서는 타입의 관계가 아니라 메서드의 리턴 타입과 파라미터의 타입에 초점을 맞춰야 한다.
  • 리턴 타입 공변성
    • 부모 클래스에서 구현된 메서드를 자식 클래스에서 오버라이딩할 때 부모 크래스에서 선언한 반환타입의 서브타입으로 지정할 수 있는 특성을 리턴 타입 공변성이라고 한다.
    • 슈퍼타입 대신 서브타입을 반환하는 것은 더 강력한 사후조건을 정의하는 것과 같다.
      • 계약을 위반하지 않는다.
    • 공변성과 반공변성의 지원 여부는 언어에 따라 다르니 주의하자.

서브타입의 메서드 파라미터는 반공변성을 가져야 한다.

  • 자바에서는 파라미터 반공변성을 허용하지 않는다.
  • 파라미터 타입 반공변성
    • 부모 클래스의 메서드를 자식 클래스에서 오버라이딩할 때 파라미터 타입을 부모 클래스에서 사용한 파라미터의 슈퍼타입으로 지정할 수 있는 특성
    • 서브타입 대신 슈퍼타입을 파라미터로 받는 것은 더 약한 사전 조건을 정의하는 것과 같다.
      • 계약을 위반하지 않는다.

함수 타입과 서브타이핑

  • 객체지향 언어들은 이름 없는 메서드를 정의할 수 있도록 허용하고 있다.
    • 익명 함수, 함수 리터럴, 람다 표현식
  • 타입에서 정의한 시그니처를 준수하는 메서드들은 해당 타입의 인스턴스로 간주한다.
  • 서브 타입의 메서드는 슈퍼 타입의 메서드를 대체할 수 있다.
profile
꾸준히 나아가자 🐢

0개의 댓글