리스코프 치환 원칙 (Liskov Substitution Principle)
상위 타입의 객체를 하위 타입의 객체로 치환해도 상위 타입을 사용하는 프로그램은 정상적으로 동작해야 한다.
이 원칙은 상속하지 말아야할 때를 생각해볼수있다.
Rectangle - Square problem
우리회사 시스템에 Rectangle.class가 필요했다고 예를 들자.
-> 코드짰다
// Rectangle.class public class Rectangle { private int width; private int height; public void setWidth(int width){ this.width = width; } public void setHeight(int height) { this.height = height; } public int getWidth() { return width; } public int getHeight() { return height; } }
어느날 Square 클래스가 필요했다.
Rectangle을 상속받아 Square 구현하기로 했다.
// Square.class public class Square extends Rectangle { @Override public void setWidth(int width) { super.setWidth(width); super.setHeight(width); } @Override public void setHeight(int height) { super.setWidth(height); super.setHeight(height); } }
세로의 길이가 더 길게 만들어주는 메소드가 있다.
public void increaseHeight(Rectangle rec) { if(rec.getHeight() <= rec.getWidth()) { rec.setHeight(rec.getWidth() + 10); } }
무엇이 문제인가?
위의 코드에서 인자로 받는 rec
객체의 구현체가
Square
일 수 있다.
분명 메소드는 세로의 길이가 더 길게 만들어 주는 기능인데..
이런? Square
이 오면 그 기능을 못한다.
가로, 세로 모두 10 증가한다.
instanceOf
그래서 다음과 같이 수정했다.
public void increaseHeight(Rectangle rec) { if(rec instanceof Square) throw new CantSupportSquareException(); if(rec.getHeight() <= rec.getWidth()) { rec.setHeight(rec.getWidth() + 10); } }
자...이렇게 짜면 잘 작동한다.
끝~~?
아니다.
이건 레거시 코드(Regacy Code)다.
OCP(Open-Close Principle)를 위반한다 !
Sqaure클래스가 Rectangle클래스를 상속받아서 수정이 필요했다.
확장하는데 기능을 사용하는 코드에 수정이 필요했다.
자주 이용하던 List로 예를 들어보면..
List list1 = new ArrayList(); List list2 = new LinkedList();
List
를 사용하는데 구현체가 ArrayList
인지 LinkedList
인지를 알아야하나?
아니다!!!
구현체를 안다는 것은 나중에 구현체가 추가/제거 되었을 때 수정해주어야 한다는 것이다.
즉, 구현체를 추가시키면 List에 추가적인 코드를 필요로 한다.
고로 OCP를 위반한다.
Liskov Substitution Principle
타입 S의 객체 o1 과 타입 T의 인스턴스 o2가 있을 때,
어떤 프로그램에서 타입 T의 객체로 P가 사용된다고 하자.
S가 T의 서브타입이라면 P에 대입된 o1이 o2로 치환 된다고 해도
P의 행위는 바뀌지 않는다.
Square가 Rectangle을 상속하는 것은 옳은가 ?
OOP에서 상속하려면 is-A 관계
를 만족시켜야 한다.
Square is a Rectangle ?
Yes?
Square = Rectangle + 각 변의 길이는 같다
수학적으로는 is-A 관계가 맞다.
그럼 상속하는게 맞는거임?
No!
상속하면 안된다.
프로그래밍적으로는 글쎄.. 행위가 다르다.
Rectangle이 수행하는 기능이 Sqaure에서도 만족시켜야 한다.
그런데 위에서도 봤듯이 만족못시키잖아..
그러니까 is-a 아니다.
해결법
음.. 인터페이스를 두고 Rectangle 과 Square이 인터페이스를 구현하면 될거같다.
면적을 구하거나 각 변의길이 설정하는 것은 뭐.. 같은 기능이니까
둬도 될거 같은데..
참고자료
'Old Posts > OOP' 카테고리의 다른 글
02. 개방-폐쇄 원칙 (Open-closed principle) (0) | 2018.03.13 |
---|---|
01. 단일 책임 원칙 (Single Responsibility Principle) (0) | 2018.02.27 |
00. 알고리즘 문제로 OOP 이해하기.md (1) | 2018.02.27 |