리스코프 치환 원칙(Liskov Substitution Principle, LSP)은 자식 클래스가 부모 클래스의 기능을 모두 대체할 수 있어야 한다는 원칙입니다. 즉, 부모 클래스 객체를 자식 클래스 객체로 대체해도 프로그램의 기능이 정상적으로 작동해야 합니다. 이를 통해 상속 관계에서 일관성과 예측 가능성을 유지할 수 있습니다.
아래 예제에서는 직사각형(Rectangle)과 정사각형(Square) 클래스를 사용하여 LSP를 적용하지 않은 경우와 적용한 경우를 보여드립니다.
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;
}
public int getArea() {
return width * height;
}
}
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 class Main {
public static void main(String[] args) {
Rectangle rect = new Rectangle();
rect.setWidth(5);
rect.setHeight(10);
System.out.println("Rectangle area: " + rect.getArea()); // 예상: 50
Rectangle square = new Square();
square.setWidth(5);
square.setHeight(10);
System.out.println("Square area: " + square.getArea()); // 예상: 50, 실제: 100
}
}
위 코드에서 Square 클래스는 Rectangle 클래스를 상속받았지만, LSP를 위반하고 있습니다. 정사각형 객체(Square)가 직사각형 객체(Rectangle)로 대체되었을 때 예상한 결과와 실제 결과가 다릅니다.
LSP를 준수하려면 Rectangle 클래스와 Square 클래스를 별도로 정의하거나, 상속을 사용하지 않고 인터페이스를 사용하는 방법을 고려할 수 있습니다.
public interface Shape {
int getArea();
}
public class Rectangle implements Shape {
protected int width;
protected int height;
public Rectangle(int width, int height) {
this.width = width;
this.height = height;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
@Override
public int getArea() {
return width * height;
}
}
public class Square implements Shape {
private int side;
public Square(int side) {
this.side = side;
}
public int getSide() {
return side;
}
@Override
public int getArea() {
return side * side;
}
}
public class Main {
public static void main(String[] args) {
Shape rect = new Rectangle(5, 10);
System.out.println("Rectangle area: " + rect.getArea()); // 예상: 50
Shape square = new Square(5);
System.out.println("Square area: " + square.getArea()); // 예상: 25
}
}
리스코프 치환 원칙을 준수하면 상속 구조에서 자식 클래스가 부모 클래스를 대체할 수 있어, 코드의 일관성과 예측 가능성을 유지할 수 있습니다. 이를 통해 소프트웨어의 유지보수성과 확장성을 향상시킬 수 있습니다. 따라서 소프트웨어 개발에서 LSP를 준수하는 것이 중요합니다.