아직은 정체성이 없는 블로그

[Design Pattern][SOLID] 리스코프 치환 법칙 LSP(Liskov Substitution Principle) 본문

Disign Pattern

[Design Pattern][SOLID] 리스코프 치환 법칙 LSP(Liskov Substitution Principle)

coooding 2020. 7. 15. 01:01

LSP(Liskov Substitution Principle)이란?


리스코프 치환 원칙(영어: Liskov substitution principle, LSP)은 바바라 리스코프가 자료 추상화와 계층 (Data abstraction and hierarchy)이라는 제목으로 기조연설을 한 1987년 컨퍼런스에서 처음 소개한 내용이다

 

아래는 원문의 일부분이다.

Barbara Liskov wrote LSP in 1988:
What is wanted here is something like the following substitution property: If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T." - BarbaraLiskov, Data Abstraction and Hierarchy, SIGPLAN Notices, 23,5 (May, 1988).

원문의 해석이 힘들다면 갓파고나 구글번역기를 이용하길 추천한다. 절대 필자가 해석하기 귀찮거나 영어를 못해서가 아니다. 크흠;;

 

위의 내용을 단순하게 풀어보자면 LSP는 일반화 관계에 대한 이야기이고 자식 클래스는 최소한 자신의 부모 클래스에서 가능한 행위는 수행할 수 있어야 한다는 뜻이다.

LSP를 만족한다면 프로그램에서 부모 클래스의 인스턴스 대신에 자식 클래스의 인스턴스로 대체해도 프로그램의 의미는 변화되지 않는다.

 

좀 더 한줄로 정리해보자면 하위 클래스는 수퍼 클래스로 대체 가능해야합니다라고 말할 수 있겠다.

 

 

 

리스코프 치환 원칙이 왜 중요한가?


1. LSP 원칙을 지키지 않으면 서브클래스 인스턴스를 파라미터로 전달 했을 때 메소드가 이상하게 작동 할 수 있습니다.

 

2. 슈퍼클래스에 대해 작성된 단위테스트가 서브클래스에 대해서는 작동되지 않을 것입니다.

 

 

 

리스코프 치환 원칙이 위배된 예제


대표적인 예제로 사각형예제를 들 수 있습니다.

아래는 높이와 너비를 가지는 Rectangle 클래스 입니다.

class Rectangle {
    private int width;
    private int height;

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

    public int getHeight() {
        return this.height;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getWidth() {
        return this.width;
    }

    public int area() {
        return this.width * this.height;
    }
}

 

아래는 위의 Rectangle을 상속받고 있는 Square라는 클래스입니다.

setHight(int value)setWidth(int value)Override하였습니다.

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

    @Override
    public void setWidth(int value) {
        this.width = value;
        this.height = value;
    }
}

 

아래는 이해를 돕기위한 test코드입니다.

너비9, 높이3으로 설정한 뒤 넓이를 구하고 확인하는 함수입니다.

class TestLSP {
    static boolean check(Rectangle r) {
        r.setWidth(9);
        r.setHeight(3);

        if(r.area() != 27 ){ // Error Size
            return false;
        }

        return true;
    }
    public static void main(String[] args){
        Test.check(new Rectangle()); //  true
        Test.check(new Square()); // false
    }
}

 

부모 클래스인 Rectangle은 결과 값을 true를 확인 할 수 있지만 Squarefalse로 확인 할 수 있습니다.

Square의 area()리턴값은 9가 나올 것 입니다.

자식 클래스 Square는 부모 클래스 Rectanglearea() 기능을 제대로 하지 못하고 있기 때문에 LSP를 위반한 하나의 예제로 볼 수 있습니다.

 

해결 방법


상속의 관계를 제거하는 방법.

기능을 제대로 하지 못하는 area()를 자식 클래스로 이동시키는 방법.

 

위 코드와 같은 문제가 발생하는 것을 막는 간단한 방법은 재정의 @Override를 하지 않는것이다.

 

 

 

참고한 자료

https://ko.wikipedia.org/wiki/%EB%A6%AC%EC%8A%A4%EC%BD%94%ED%94%84_%EC%B9%98%ED%99%98_%EC%9B%90%EC%B9%99 
https://code.tutsplus.com/tutorials/solid-part-3-liskov-substitution-interface-segregation-principles--net-36710
책 JAVA 객체 지향 디자인 패턴(UML과 GoF 디자인 패턴 핵심 10가지로 배우는), 정인상, 채홍석 지음, 한빛미디어
Comments