ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • '오브젝트' 책 보고 공부하기 - (부록A) 계약에 의한 설계
    JAVA공부/JAVA 2023. 7. 10. 02:39

    1) 협력과 계약

     

    계약에 의한 설계 라이브러리를 사용한다면

    Contract.Requires(IsSatisfied(schedule));

     

    와 같이 제약조건을 명시적으로 표기할 수 있다.

    이는 주석과 다르게 시간의 흐름에 따라 같이 움직이며, 실행중에도 체크할 수 있다.

     

    은 일반적으로 다음과 같은 특성이 있다.

    ● 각 계약 당사는 계약으로부터 이익을 기대하고 이익을 얻기 위해 의무를 이행한다.

    ● 각 계약 당사자의 이익과 의무는 계약서에 문서화 된다.

     

    계약 이라는 아이디어를 통해 객체 협력 방식에 적용한 아이디어가 있다.

    다음 내용을 살펴보자.

     

     


     

    2) 계약에 의한 설계

     

    계약의 의한 설계 개념은 "인터페이스에 대해 프로그래밍하라"는 원칙을 확장한 것이다.

    다음 자바코드를 보자


    가시성 / 반환 타입 / 메서드 이름  
    public    Member    save (


    파라미터 String     name  파라미터명
          타입   int            age                     )

     

    public을 가지기 때문에 외부에서 호출가능하며 이 메서드를 사용하기 위해서는 String 타입int 타입

    인자를 전달 해야한다. 메서드 실행이 끝나면 Member타입의 인스턴스를 반환해준다.

     

    이것만으로 끝나지 않는다. 서버와 클라이언트가 기대하는것

    서버는 자신이 받을 수 있는 (파라미터들의)값의 범위인지,

    클라이언트는 자신이 원하는 값을 받는지,

    메시지 전송 전후 서버 상태가 정상인지 

    이 세가지가 계약에 의한 설계를 구성하는 세가지 요소이며 자세히보자면 다음과 같다.


    사전조건

    메서드가 정상적으로 실행되기 위한 조건

    (save메서드에서는 name은 null이어서는 안되고, age는 0이상이어야한다.)

     

    사후조건

    메서드의 실행 결과가 올바른지 검사하고 실행 후에 유효한 상태로 객체가 남아 있는지 검증

    (save메서드에서 반환해주는 Member가 Null이어서는 안된다.)

    위와 다른 경우가 있다.

    ● 한 메서드 안에서 return문이 여러번 나올 경우

    return문마다 결과값이 올바른지 검증하는 코드를 추가해야하지만, 라이브러리(계약에 의한 설계) 를 사용하면

    하나의 검증 코드만 추가하여도 된다.

     

    ● 실행 전과 실행 후의 값을 비교해야 하는 경우

    이것도 라이브러리 도움을 받아 실행전의 값에 접근할 수 있는 방법을 제공하고 있어서 해당값과 결과값을 비교하면된다.

     

    불변식

    항상 참이라고 보장되는 서버의 조건 

    메서드 실행되는 도중 불변식을 만족시키지 못할 수 있으나, 실행 전 종료 후에는 항상 참이어야한다.

    인스턴스 생명 주기 전반에 걸쳐 지켜져야한다. (일반적으로 객체 내부의 상태)

    원래는 생성자 실행후, 메서드 실행전에 사전조건과 함께, 메서드 실행 후 사후 조건과 함께 실행되어야 하지만

    라이브러리를 사용하면 모든 메서드, 생성자에 적용을 시켜준다. 

     


     

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

     

    리스코프 치환 원칙의 규칙을 두가지로 세분화 한다면


    계약 규칙

    슈퍼타입과 서브타입 사이의 사전조건, 사후조건, 불변식에 대해 서술할 수 있는 제약에 관한 규칙

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

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

    - 슈퍼타입 불변식은 서브타입에서도 유지되어야 한다.

    (실행 중간에 상태 변경시 불변식을 만족하지 않을 수가 있다.)

     

    가변성 규칙

    파라미터와 리턴타입의 변형과 관련된 규칙

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

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

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

    (클라이언트가 catch를 통해 예외 처리를 할 수 없음)

     

    공변성, 반공변성, 무공변성의 개념

    S가 T의 서브타입인 경우 두 타입 사이의 치환가능성을 나눠 볼 수 있다.

     

    공변성

    S와 T사이의 서브타입 관계가 그대로 유지 서브타입인 S가 슈퍼타입 T 대신 사용 될 수 있다. (리스코츠 치환원칙)

     

    반공변성

    S와 T사이의 서브타입 관계가 역전된다. 슈퍼타입인 T가 서브타입인 S 대신 사용될 수 있다.

     

    무공변성

    S와 T사이에 아무런 관계가 존재하지 않는다. S대신 T 혹은 T대신 S를 사용할 수 없다.

     

    리턴타입의 공변성은 클라이언트가 요청한 메서드의 리턴값인 슈퍼타입을 대신해서 서브타입을 사용할 수 있는 경우를 말한다.

    부모 클래스 public Car sell() {}

    자식 클래스 public HybridCar sell() {}

    치환을 진행하더라도 클라이언트는 같은 타입으로 보기때문에 문제가 없다.

    간단히 말해서 메서드를 구현한 클래스의 타입 계층방향과 리턴 타입의 계층 방향이 동일한 경우를 말한다.

    슈퍼타입 대신 서브타입을 반환하는 것은 더 강력한 사후조건을 정의하는 것과 같으므로 계약을 위반하지 않는다.

     

    다만, 이는 언어에 따라 지원하는 것이 다르며 자바에서는 리턴타입에 대해 지원하지만, C#은 지원하지 않는다.(무공변성)

     

    파라미터 반공변성은 예시를 보자면 다음과 같다.

    부모 클래스 public void upgrade(SuperCarCenter superCarCenter) {}

    자식 클래스 public void upgrade(CarCenter carCenter){}

    (자바에서는 안된다. -> 메소드 오버로딩으로 판단)

    즉, 부모 클래스에서 구현된 메서드를 자식클래스에서 오버라이딩 할 때 파라미터 타입을 부모 클래스에서 사용한 

    파라미터의 슈퍼타입으로 지정할 수 있는 특성파라미터 타입 반공변성이라고 한다.

    서브타입 대신 슈퍼타입으로 파라미터 타입을 받는 것은 사전조건을 완화하는 행위와 같다.

     

    대부분의 언어는 반공변성을 지원하지 않지만, 제네릭 프로그래밍에서 중요한 의미를 가지기 때문에 기본적인 내용은 알고가자.

     

    진정한 서브타이핑 관계를 만들고자 한다면, 서브타입에 더 강력한 사전조건이나 더 완화된 사후조건을 정의하지 말고

    슈퍼타입의 불변식을 유지하기 위해 노력해야한다. 그리고 서브타입에서 슈퍼타입에서 정의하지않은 예외를 던져서는 안된다.

     

     

     

     

     

     

     

Designed by Tistory.