public class SuperClass {
public int someMethod() {
// 항상 양의 정수를 반환
return 1;
}
}
public class SubClass extends SuperClass {
@Override
public int someMethod() {
// 음의 정수를 반환
return -1;
}
}
SuperClass
의 someMethod
가 항상 양의 정수 반환SubClass
의 someMethod
가 항상 음의 정수 반환Rectangle
클래스를 통해 직사각형을 표현하는 경우가로 - width
세로 - height
값을 설정하고 가져오는 메서드 제공
public class Rectangle {
protected int width;
protected 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;
}
}
정사각형의 경우 모든 변의 길이가 같은 직사각형의 일종이다.
Rectangle
크래스를 상속해 Square
클래스를 만드는 경우
정사각형의 경우 가로, 세로가 동일해야하기에,
public class Square extends Rectangle {
@Override
public void setWidth(int width) {
this.width = width;
this.height = width; // 가로와 세로를 동일하게 설정
}
@Override
public void setHeight(int height) {
this.width = height; // 가로와 세로를 동일하게 설정
this.height = height;
}
}
직사각형 클래스에서 만약에
public void increaseHeight(Rectangle rec) {
if (rec.getHeight() <= rec.getWidth()) {
rec.setHeight(rec.getWidth() + 10);
}
}
같은 가로, 세로 길이를 조정하는 메서드가 등장한 경우
정사각형 객체 Square
의 경우 상당히 곤란해진다
그래서 개발자는 급하게 직사각형의 객체에서
public void increaseHeight(Rectangle rec) {
if (rec instanceof Square) {
throw new IllegalArgumentException("Square 객체는 지원되지 않습니다.");
}
if (rec.getHeight() <= rec.getWidth()) {
rec.setHeight(rec.getWidth() + 10);
}
}
하위 클래스에서 사용하지 못하도록 instanceof 를 통해 사용 객체를 제한한다.
LSP 상에서 분명히
만약 해당 2가지 타입의 경우에는 상속이 아니도록 다른 도메인으로 분리하거나, Square
클래스내에서 멤버 변수로 선언하는 등의 행위가 있다.
public abstract class InputStream {
public abstract int read(byte[] data) throws IOException;
}
public class CopyUtil {
public static void copy(InputStream is, OutputStream os) throws IOException {
byte[] buffer = new byte[512];
int len;
while ((len = is.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
}
}
-1
을 반환하도록 정의되어 있다고 합니다.read
메서드가 데이터를 더 이상 읽을 수 없다면 0
을 반환하도록구현되어 있다면 문제가 발생합니다. public class ZeroReturningInputStream extends InputStream {
@Override
public int read(byte[] data) throws IOException {
// 데이터가 없을 때 0을 반환
return 0;
}
}
InputStream is = new ZeroReturningInputStream();
OutputStream os = new FileOutputStream("output.txt");
CopyUtil.copy(is, os); // 무한 루프 발생
ZeroReturningInputStream
가 InputStream 의 계약을 준수하지 않는다고 볼 수 있습니다.기능의 명세
또는 계약
에 관한 내용이다.직사각형 - 정사각형 문제
에서 Rectangle
클래스에서 setHeight
메서드는Square
클래스에서IOException
만 발생시키도록 명세IllegalArgumentException
를 발생시킴확장
이 주요합니다.LSP
를 준수하기 어렵다고 합니다.public class Coupon {
public int calculateDiscountAmount(Item item) {
return item.getPrice() * discountRate;
}
}
Item
객체의 가격을 기반으로 할인 금액을 계산하는데,
특정 상품은 할인에서 제외해야하는 요구사항이 생겨
SpecialItem
이라는 하위 클래스를 추가했다고 가정한다
public class Coupon {
public int calculateDiscountAmount(Item item) {
if (item instanceof SpecialItem) // 리스코프 치환 원칙 위반
return 0;
return item.getPrice() * discountRate;
}
}
해당 케이스는 SpecialItem
이 상위 타입인 Item
을 완전히 대체하지 못함을 보여준다.
LSP 를 위반하는 것이다.
문제점
해결방안
해결을 위하여 추상화 수준
을 증대해야함
public class Item {
public boolean isDiscountAvailable() {
return true;
}
}
public class SpecialItem extends Item {
@Override
public boolean isDiscountAvailable() {
return false;
}
}
isDiscountAvailable 를 통하여 각 객체가 할인 가능 한지 추가하고
public class Coupon {
public int calculateDiscountAmount(Item item) {
if (!item.isDiscountAvailable())
return 0;
return item.getPrice() * discountRate;
}
}
해당 아이템의 상위 ~ 하위 타입까지 할인가능 여부를 고려하면 된다.