PR CENTER

뉴스룸     |     료실

mobile background

PR CENTER

리스코프 치환 원칙

관리자
2025-10-27
조회수 51

리스코프 치환 원칙


Parent c = new Parent();
Parent p = new Child();  // 정상 작동

LSP 에 따라 위 코드가 문제없이 동작하려면 하위 클래스(Child)가 상위 클래스(Parent)의 행위를 완전히 대체할 수 있도록 설계되어야 한다.

LSP의 핵심은 부모 클래스의 행동 규약을 자식 클래스가 위반하면 안 된다는 것이다.


컴포지션 방법 사용

  • LSP는 다형성의 원칙을 지키도록 강제하는 규칙으로 볼 수 있다.
  • 컴포지션 방식을 사용할 때, 부모 클래스의 기능을 유연하게 사용할 수 있다.

→ 따라서 LSP 에 따른 객체 지향 관계의 클래스 간의 관계를 표현할 때, 상속보다 컴포지션이 더 적절할 수 있다.

  1. 상속 (is-a) : 행동을 정의한 상속
  2. 컴포지션 (has-a) : 포함 관계를 정의한 다중 상속

LSP를 위반한 예시

다음은 LSP 위반 예시로 유명한 사각형 넓이 구하기 이다.

Rectangle 클래스


@Getter
@Setter
public class Rectangle {
    private int width;
    private int height;
    
    public int area() {
        return width * height;
    }
}

Square 클래스


public class Square extends Rectangle {

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

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

LspMain 테스트


public class LspMain {
    public static void main(String[] args) {
        System.out.println("\n==== 부모(Rectangle) 클래스 ====");
        Rectangle rectangle = new Rectangle();
        rectangle.setWidth(4);
        rectangle.setHeight(5);
        System.out.println("넓이 = " + rectangle.area());

        System.out.println("\n===== 자식(Square) 으로 대체 ====");
        Rectangle square = new Square();
        square.setWidth(4);
        square.setHeight(5);

        System.out.println("넓이 = " + square.area());

        System.out.println("\n====== 동일한 결과 값 인가? ======");
        System.out.println(rectangle.area() == square.area() );
    }
}

출력 결과


==== 부모(Rectangle) 클래스 ====
넓이 = 20

===== 자식(Square) 으로 대체 ====
넓이 = 25

====== 동일한 결과 값 인가? ======
false

문제점

  1. 부모 클래스의 행동 규약을 위반한 자식 클래스
    • Rectangle의 규약: width와 height를 독립적으로 설정
    • Square의 규약: width와 height가 항상 동일
  2. → 메서드의 예상 동작이 변경됨 → LSP 위반

  3. 실패한 상속 관계

    Square는 수학적으로 Rectangle의 특수한 형태지만, 동작 방식이 다르므로 OOP 관점에서는 상속관계가 적절하지 않다.

→ Square 과 Rectangle 을 개별 클래스로 분리 후, 컴포지션 방식으로 리팩토링 해보자


LSP를 준수한 예시

상속 대신 컴포지션 방식을 사용해 LSP를 준수한 코드로 변경했다.

Shape 인터페이스


public interface Shape {
    int area();
}

Rectangle 클래스


@Getter
@AllArgsConstructor
public class Rectangle implements Shape {
    private int width;
    private int height;

    @Override
    public int area() {
        return width * height;
    }
}

Square 클래스


@Getter
@AllArgsConstructor
public class Square implements Shape {

    private int side;

    @Override
    public int area() {
        return side * side;
    }
}

LspMain 테스트


public class LspMain {
    public static void main(String[] args) {
        System.out.println("\n==== 부모(Rectangle) 클래스 ====");
        Shape rectangle = new Rectangle(4, 5);
        System.out.println("넓이 = " + rectangle.area());

        System.out.println("\n===== 자식(Square) 으로 대체 ====");
        Shape square = new Square(3);

        System.out.println("넓이 = " + square.area());

        System.out.println("\n====== 동일한 결과 값 인가? ======");
        System.out.println(rectangle.area() == square.area() );
    }
}

출력 결과


==== 부모(Rectangle) 클래스 ====
넓이 = 20

===== 자식(Square) 으로 대체 ====
넓이 = 16

====== 동일한 결과 값 인가? ======
false

결과

  • Rectangle, Square 각각 규약에 맞는 동작을 한다.
  • 두 클래스 모두 Shape 인터페이스의 행위를 대체할 수 있다.
  • 구현 클래스를 교체해도 원하는 결과 값을 얻을 수 있다.


                                                                                                                                                                                                                                               ⭐발표자 : 이현진님

0 0

페이지 바로가기

@2024 K2SYSTEMS. All rights reserved.

HOME       |       ABOUT US       |       SOLUTION       |       PR CENTER       |       CONTACT       |       인재채용       |       kakao i cloud 고객센터  

@2024 K2SYSTEMS. All rights reserved.