Home 리스코프 치환 원칙
Post
Cancel

리스코프 치환 원칙

리스코프 치환 원칙

  • 타입 S가 타입 T의 서브타입이라면 프로그램의 속성 변경없이 T 타입의 객체를 S 타입으로 치환할 수 있어야한다.
    • 즉 쉽게 말해 부모 객체를 호출하는 동작에서 자식 객체가 부모 객체를 완전히 대체할 수 있다

요구사항

    1. 서브 타입에서 메소드 파라미터 타입은 반공변성(Contravariance)
    1. 서브 타입에서 메소드 return 타입의 공변성(Covariance)
    1. 서브 타입에서 메소드는 상위 클래스의 메소드에서 throw한 하위형을 제외하고 새로운 예외를 던질 수 없음
여기서 말하는 공변성과 반공변성이란?
공변성은 한 변수가 변하면 다른 변수도 변하는 성질을 말하며, 반공변성은 그 반대의 성질을 말한다. 위의 요구사항을 해석하면 리턴 타입 이나 예외의 경우 부모 객체가 의도하는 리턴타입을 자식이 마음대로 바꾸면 안된다는 것을 의미한다.

문제

1
2
3
4
5
6
7
8
9
10
11
12
13
@Getter @Setter
public class Rectangle {
  protected int width;
  protected int height;

  public Rectangle(int width, int height) {
    this.width = width;
    this.height = height;
  }
  public Number getArea() {
    return height*width;
  }
}

위와 같이 2개의 값을 받아 넓이를 구해주는 클래스가 있다고 하자.

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Square extends Rectangle{
  @Override
  public void setWidth(int width) {
    super.setWidth(width);
    super.setHeight(width);
  }

  @Override
  public void setHeight(int height) {
    super.setHeight(height);
    super.setWidth(height);
  }
}

정사각형은 직사각형을 상속받아 값이 들어올 경우 정사각형이기때문에 밑변과 높이를 모두 똑같이 하도록 오버라이딩을 했다.

1
2
3
4
5
6
7
8
9
public class Main {

  public static void main(String[] args) {
    Rectangle rectangle = new Rectangle();
    rectangle.setWidth(10);
    rectangle.setHeight(5);
    System.out.println(rectangle.getArea());
  }
}

위의 결과는 부모 클래스에 의도에 의하면 50이 나와야 하지만 위의 경우 25가 나온다. 이는 리스코프 치환 원칙을 위배하게 되는 것이다.

문제 해결

  • 위의 경우를 통해 직사각형과 정사각형은 상속관계가 성립될거 같지만 성립되지 않는다. 그렇기 때문에 더 상위 클래스를 만들어 이들이 상속 받도록 하면된다.
1
2
3
public interface Shape {
    Number getArea();
}

위와 같이 Shape라는 상위 인터페이스를 생성한다.

1
2
3
4
5
6
7
8
9
10
11
public class Square implements Shape {
    int length;

    public Square(int length) {
        this.length = length;
    }
    @Override
    public Number getArea() {
        return length*length;
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Rectangle implements Shape {
    int width;
    int height;

    public Rectangle(int width, int height) {
        this.width = width;
        this.height = height;
    }
    @Override
    public Number getArea() {
        return width*height;
    }
}

이렇게 정사각형과 직사각형이 Shape 에게 상속을 받도록 구현한다.

1
2
3
4
5
6
7
8
9
public class Main {

  public static void main(String[] args) {
    Shape rectangle = new Rectangle(5);
    Shape square = new Square(10,5);
    System.out.println(rectangle.getArea());
    System.out.println(square.getArea());
  } // 25 : 50
}

직사각형과 정사각형은 직접적인 상속관계가 없기 때문에 위에서 발생했던 리스코프 치환 원칙을 위반하지 않고 사용할 수 있다.

This post is licensed under CC BY 4.0 by the author.