하위 타입

여기에서 필요한 것은 다음과 같은 치환 원칙이다.
S 타입의 객체 o1 각각에 대응하는 T 타입 객체 o2가 있고,
T 타입을 이용해서 정의한 모든 프로그램 P에서 o2의 자리에 o1을 치환하더라도 P의 행위가 변하지 않는다면,
-> S는 T의 하위 타입이다.

상속을 사용하도록 가이드

License라는 클래스가 있다고 해보자
calcFee() 메서드를 가지며 Billing Application이 메서드를 호출한다.
License는 PersonalLicense와 BusinessLicense라는 두가지 '하위 타입' 을 갖는다.
두 하위 타입은 서로 다른 알고리즘을 이용해서 메서드를 오버라이드 한다.

이 설계는 LSP를 준수한다.
-> Billing App의 행위가 License 하위타입중 무엇을 사용하는 지에 전혀 의존하지 않기 때문이다.

정사각형/직사각형 문제

LSP를 위반하는 전형적인 문제

Square는 Rectangle의 하위 타입으로는 적합하지 않은데,
Rectangle의 높이와 너비는 서로 독립적으로 변경될 수 있는 반면,
Square의 높이와 너비는 반드시 함께 변경되기 때문이다.
User는 대화하고 있는 상대가 Rectangle이라고 생각하므로 혼동이 생길 수 있다.

Rectangle r = ...
r.setW(5);
r.setH(2);
assert(r.area() == 10);

...코드에서 Square를 생성한다면 assert문은 실패하게 된다.
-> W든 H든 변경될 때, 정사각형은 W와 H를 모두 바꾸기 때문
이런 형태의 LSP 위반을 막기 위한 유일한 방법은
if문과 같은 조건을 이용해서 Rectangle이 실제로는 Square인지를 검사하는 메커니즘을 User에 추가하는 것이다.
-> 하지만 이렇게 하면 Userdㅢ 행위가 사용하는 타입에 의존하게 되므로 타입을 서로 치환할 수 없게 된다.

LSP와 아키텍처

객체 지향이 등장한 초창기에는 LSP는 상속을 사용하도록 가이드되었다.
하지만 시간이 지나면서 LSP는 인터페이스와 구현체에도 적용되는 더 광범위하게 변했다.

여기서 말하는 인터페이스는 다양한 형태로 나타난다.
자바스러운 언어라면 인터페이스 하나와 이를 구현하는 여러개의 클래스로 구성
잘 정의된 인터페이스와 그 구현체끼리의 상호 치환 가능성에 기대는 사용자들이 존재하기 때문이다.

LSP 위배 사례

  1. 다양한 택시 파견 서비스를 통합하는 App을 만들고 있다고 가정하자.

  2. 고객은 어느 택시업체인지는 모르지만 자신의 상황에서의 적절한 택시를 찾는다.

  3. 고객이 이용할 택시를 결정하면, 시스템은 REST 서비스를 통해 선택된 택시를 고객 위치로 파견한다.

  4. 택시 파견 REST 서비스의 URI가 운전기사 DB에 저장되어 있다고 가정해보자

  5. 시스템이 고객에게 알맞은 기사흫 선택하면, 해당 기사의 레코드로부터 URI를 얻어 해당 기사를 고객 위치로 파견한다.

EX
택시기사 Bob의 파견 URI = purplecab.com/driver/Bob
시스템은 기사 URI에 정보를 붙힌다.
purplecab.com/driver/Bob/pickupAddress/24 Maple St./pickupTime/153/destination/ORD

이 예제에서 분명한 것은 파견 서비스를 만들 때, 다양한 택시업체에서 동일한 REST 인터페이스를 반드시 준수하도록 만들어야 한다는 사실이다.
서로 다른 택시업체가 pickupAddress/pickupTime/destination 을 동일하게 처리해야 한다.

이제 택시업체(kakaoTaxi)에서 프로그래머를 몇 명 고용했는데, 서비스 사양서를 신중히 읽지 않았다고 가정하자.
destination 필드를 dest로 축약했다.
그렇다면 파견 서비스에서는 kakaoTaxi만을 위해 모든 모듈에

if(driver.getDispatchUri().startsWith("kakaoTaxi")).....

를 추가해야 할 것이다.

결론

LSP는 아키텍처 수준까지 확장할 수 있고, 반드시 확장해야만 한다.
치환 가능성을 조금이라도 위배하면 시스템 아키텍처가 오염되어 별도의 코드/메커니즘이 필요할 수도 있다.

+ Recent posts