안녕하세요. 오늘은 SOLID 원칙 중 LSP에 대해서 알아보겠습니다.
이전 원칙인 SRP, OCP에 대해서 알고 싶으시다면 아래 게시글에서 확인하실 수 있습니다.
2024.05.30 - [DeepDive] - 객체지향원칙(SOLID) - SRP(Single Responsibility Principle)
2024.05.30 - [DeepDive] - 객체지향원칙(SOLID) - OCP(Open-Closed Principle)
LSP란 무엇인가?
LSP는 Liskov Substitution Principle의 약자로, 한국어로는 리스코브 치환 원칙이라고 합니다. 여기서 리스코브는 사람이름입니다. 바바라 리스코브라는 분이 처음 만든 개념입니다.
이 원칙에 대해서 간단히 설명하자면 '하위 타입은 상위 타입으로 간단히 치환될 수 있어야 한다.'라는 원칙입니다.
아래 코드를 볼까요?
interface Shape {
double calcArea();
}
class Rectangle implements Shape {
private int width;
private int height;
public Rectangle(int width, int height) {
this.width = width;
this.height = height;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
@Override
public double calcArea() {
return width * height;
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
Shape shape = new Rectangle(10, 20);
System.out.println(shape.calcArea());
}
}
보시는 것처럼 상위 타입인 Shape에 하위 타입인 Rectangle이 할당되는 것을 볼 수 있습니다.
또한 calcArea 메서드를 실행했을 때 정상적으로 Rectangle 클래스의 calcArea 메서드가 실행될 것입니다.
이렇게 치환될 수 있어야 한다는 것이 바로 LSP입니다.
LSP 위반
이번에는 LSP 위반에 대해서 알아보겠습니다. 흔히 알려진 LSP 위반은 상위타입이 '직사각형', 하위타입이 '정사각형' 일 때 발생합니다.
class Rectangle {
private int width;
private int height;
public Rectangle(int width, int height) {
this.width = width;
this.height = height;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
}
class Square extends Rectangle {
public Square(int sideLength) {
super(sideLength, sideLength);
}
@Override
public int getWidth() {
return super.getWidth();
}
@Override
public void setWidth(int sideLength) {
super.setHeight(sideLength);
super.setWidth(sideLength);
}
@Override
public int getHeight() {
return super.getHeight();
}
@Override
public void setHeight(int sideLength) {
super.setHeight(sideLength);
super.setWidth(sideLength);
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
Rectangle rectangle = new Square(10);
// 큰 문제 없음
System.out.println(rectangle.getHeight());
System.out.println(rectangle.getWidth());
/**
* 이건 문제가 있음.
* 분명 다루는 타입은 rectangle 이라서 setHeight 를 하면 높이만 변경될 것으로 기대함.
* 하지만 실제 객체는 Squere 이라서 넓이도 동시에 바뀜.
* 이는 LSP를 위반하는 것임.
*/
rectangle.setHeight(11);
System.out.println(rectangle.getHeight());
System.out.println(rectangle.getWidth());
}
}
코드를 보면 Rectangle 타입에 Square를 할당하는 것을 볼 수 있습니다. 하지만 변수는 Rectangle 타입이기 때문에 이 문맥을 다룰 때는 Rectangle을 다룬다고 생각하게 됩니다.
이때 Rectangle의 높이를 변경하고자 합니다. 그렇다면 사용자는 높이만 변경되는 것을 기대합니다. 하지만 Square는 정사각형이기 때문에 높이, 너비가 모두 변경되고 맙니다. 의도치 않은 동작이 발생하는 것이죠.
이는 '간단히 치환되지 않은 것'입니다. 이를 해결하기 위해서 추가적인 방법이 더 필요할 테니까요.
마치며
이번에는 LSP에 대해서 알아보았습니다. LSP는 DIP에도 적용될 만큼 중요합니다. 저 또한 이 개념과 DIP와 많이 헷갈렸었는데, 정리를 통해서 해결했습니다. 여러분의 정리에 큰 도움이 되길 바랍니다.
'DeepDive' 카테고리의 다른 글
객체지향원칙(SOLID) - ISP(Interface Segregation Principle) (0) | 2024.06.19 |
---|---|
객체지향원칙(SOLID) - OCP(Open-Closed Principle) (0) | 2024.05.30 |
객체지향원칙(SOLID) - SRP(Single Responsibility Principle) (0) | 2024.05.30 |