LSP(Liskov-Substitution Principle)
자식클래스는 부모 클래스에서 가능한 행위를 모두 수행할 수 있어야한다.
위의 정의는 자식클래스가 부모클래스를 대체할 수도 있어야 하고 일반화 관계를 의미한다.
일반화 관계는 is a kind of
관계이다. 원숭이와 포유류는 is a kind of
관계가 맞다.
포유류는 아래와 같은 조건을 만족해야한다.
- 알을 낳지 않고 새끼를 낳을 것
- 젖을 먹여 새끼를 키우고 폐를 통해 호흡할 것
- 체온이 일정한 정온 동물이며 털이나 두꺼운 피부로 덮혀 있을 것
원숭이는 위와 같은 원칙을 모두 만족하지만 오리너구리는 알을 낳아 번식하는 동물이므로 만족하지 않는다. 따라서 오리구리는 포유류에 만족하지 않아, LSP에 위배된다.
public class Bag {
private int price;
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
위와 같은 Bag
클래스에서 아래와 같은 법칙을 만족하는데
[new Bag().setPrice(1000)].getPrice() == 1000;
위의 코드 중 [ ]
는 내부에 사용된 객체를 반환한다, 즉 new Bag()
을 반환하는데, 결과적으로 set한 값이 get값으로 이상잆이 반환되는지 확인하는 코드가 된다.
LSP룰을 만족하려면 아래와 같이 기존 코드의 수정이나 값을 수정없이 그대로 사용되어야한다.
public class DiscountableBag extends Bag {
private double discountedRate = 0;
public void setDiscountedRate(double discountedRate) {
this.discountedRate = discountedRate;
}
public int getDiscountedPrice() {
return (int) (this.getPrice() * (1-discountedRate));
}
}
그럼 여전히 [new Bag().setPrice(1000)].getPrice() == 1000
가 만족하는 것을 알 수 있다. 왜냐하면 getPrice()
에는 전혀 수정을 가하지 않았기 떄문이다.
하지만 여전히 아래와 같이 코드를 쓰는 사람은 굉장히 많다.
public class WrongDiscountableBag extends Bag {
private double discountedRate = 0;
public void setDiscountedRate(double discountedRate) {
this.discountedRate = discountedRate;
}
@Override
public int getPrice() {
return (int) (super.getPrice() * (1-discountedRate));
}
}
이 같은 경우 기존의 getPrice()
를 Override 했으므로 [new Bag().setPrice(1000)].getPrice() == 1000
만족하지 않아 LSP원칙에 위배된다.
아래와 같은 피터코드 상속 규칙과 동일한 원칙이라고 생각해도 된다.
서브 클래스가 슈퍼 클래스의 책임을 무시하거나 재정의하지 않고 확장을 수행한다.
'소프트웨어' 카테고리의 다른 글
[소프트웨어/SOLID] 의존 역전 원칙(DIP) (0) | 2017.01.18 |
---|---|
[소프트웨어/SOLID] 인터페이스 분할 법칙(ISP) (0) | 2017.01.18 |
[소프트웨어/SOLID] 개방 폐쇄 원칙(OCP) (0) | 2017.01.18 |
[소프트웨어/SOLID] 단일 책임 원칙(SRP) (0) | 2017.01.18 |
[소프트웨어] 객체지향의 기본원리 정리 (0) | 2017.01.17 |