[SOLID] 리스코프 치환 원칙(LSP) 위배 예제

Hyejin Kim·2025년 3월 24일
0
post-thumbnail

아래 코드를 살펴보자.

class Rectangle {
  int width;
  int height;

  public void setHeight(int value) {
    this.height = value;
  }
}

class Square extends Rectangle {
  @Override
  public void setHeight(int value) {
    this.height = value;
    this.width = value;
  }
}

사각형 Rectangle이 있고, 정사각형 Square는 Rectangle을 상속받는다.
height를 바꾸려고 하면, 정사각형의 특성 상 height와 width를 모두 변경한다.

위 예제는 LSP를 위배할까?

정답은 "위배한다" 이다.

먼저 LSP(리스코프 치환 원칙)란, 다음과 같다.

하위 클래스는 상위 클래스의 행위를 깨뜨리지 않으면서 상위 클래스를 대체할 수 있어야 한다.

위배되는 이유는 다음과 같다.

1. Rectangle과 Square의 행위가 다르다.

Rectangle에는 width, height를 독립적으로 설정할 수 있다.
하지만 Square는 height를 설정할 때 width도 동시에 변경된다.

Rectangle rect = new Square();
rect.setHeight(10);
System.out.println(rect.width); // 예상: 기본값(변경 X), 실제: 10

이 경우 Rectangle의 기본 가정인 "width, height를 독립적으로 설정할 수 있다."는 가정이 깨진다.
즉, Rectangle을 사용하는 코드에서 Square로 대체했을 때 예측하지 못한 동작이 발생할 수 있다.

2. 클라이언트 코드가 Rectangle의 동작을 가정하고 있는 경우 문제

public void resizeRectangle(Rectangle rect) {
    rect.setHeight(10);
    rect.setWidth(20);
    assertThat(rect.width * rect.height).isEqualTo(200);  // Error
}

여기서는 setHeight(10), setWidth(20)을 적용하면 넓이가 200 이상이 될 것이라고 가정한다.
하지만 rect가 Square라면 setWidth(20) 호출 시 height도 20이 되어 예상과 다르게 동작한다.

정리

  • Square는 Rectangle이 가진 인터페이스인 "독립적인 setHeight()와 setWidth()가 가능하다." 라는 가정을 깨버린다.
  • 따라서 Square는 Rectangle을 완전히 대체할 수 없다. -> 리스코프 치환 원칙을 위배한다.

여기서 LSP를 준수하려면?

인간이 개념적으로 이해하기로는 정사각형이 사각형의 한 종류라고 볼 수 있지만, 사실 Rectangle과 Square는 본질적으로 다르게 동작한다.
따라서 상속 관계를 제거하고 별개의 클래스로 만드는 것이 좋다.

class Rectangle {
	private int width;
    private int height;
    
    public int getArea() {
    	return width * height;
    }
}

class Square {
	private int side;
    
    public int getArea() {
    	return side * side;
    }
}

profile
Backend Engineer

0개의 댓글

관련 채용 정보