리스코프 치환 원칙(Liskov Subsitution Principle, LSP)

2024. 7. 1. 18:20· Spring/Spring Framework
목차
  1. 리스코프 치환 원칙: Liskov Subsitution Principle
  2. 요구사항
  3. LSP를 준수하지 않은 코드
  4. LSP를 준수한 코드

리스코프 치환 원칙: Liskov Subsitution Principle


리스코프 치환 원칙은 다음과 같이 정의할 수 있습니다.

  • 서브 타입은 언제나 자신의 수퍼 타입으로 교체할 수 있어야 한다.
  • 클래스의 경우 하위 클래스는 상위 클래스의 한 종류여야 한다.
  • 인터페이스인 경우 구현 클래스는 인터페이스를 지켜야 한다.

 

리스코프 치환 원칙은 코드의 재사용성, 확장성, 유지보수성을 높이는 데 중요한 역할을 합니다.

해당 원칙의 핵심 키워드는 다음과 같습니다.

  • 수퍼 타입: 부모 클래스, 서브타입이 상속받는 클래스를 의미한다.
  • 서브 타입: 자식 클래스, 부모 클래스의 특성을 상속받아 확장하거나, 구체화 한 타입을 의미한다.
  • 교체: 부모 클래스의 인스턴스를 자식 클래스로 대체해도 기능에 문제가 없어야 한다.

리스코프 치환 원칙은 올바른 상속을 위해 자식 클래스가 부모 클래스의 방향을 온전히 따르도록 하는 원칙입니다.

LSP를 설명하기 위해 간단한 예제를 통해 설명하겠습니다.

 

요구사항


  1. 직사각형(Rectangle)과 정사각형(Square)을 구현하려고 한다.
  2. 서로 가로(width)와 세로(height) 속성을 가진다.
  3. 각 구현체는 넓이를 구할 수 있다.

 

LSP를 준수하지 않은 코드


정사각형은 직사각형의 한 종류이므로 직사각형(Rectangle)을 구현 후, 상속하여 정사각형(Square)을 구현해 볼 수 있을 것 같습니다.

직사각형(Rectangle):


            
public class Rectangle {
private int width;
private int height;
public int getWidth() {
return this.width;
}
public int getHeight() {
return this.height;
}
public void setWidth(int width) {
this.width = width;
}
public void setHeight(int height) {
this.height = height;
}
// 넓이 반환
public int getArea() {
return this.width * this.height;
}
}

정사각형(Square):


            
class Square extends Rectangle {
@Override
public void setWidth(int width) {
this.width = width;
this.height = width; // 정사각형은 가로와 세로가 같아야 함
}
@Override
public void setHeight(int height) {
this.width = height;
this.height = height; // 정사각형은 가로와 세로가 같아야 함
}
}

위 코드처럼 Rectangle 클래스를 상속하여 Square 클래스를 쉽게 구현할 수 있습니다. 

 

앞서 설명한 LSP 원칙은 부모 클래스(Rectangle)와 자식 클래스(Square)는 서로 교체되어도 기능에 문제가 없어야 합니다. 구현한 Rectangle의 넓이를 구해보겠습니다.


            
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

LSP를 위배하지 않았다면 Rectangle 클래스를 상속 받은 Square 클래스도 동일하게 50으로 결괏값이 나와야 합니다.


            
public class Main {
public static void main(String[] args) {
Rectangle rectangle = new Square(); // Rectangle -> Square 교체
rectangle.setWidth(10);
rectangle.setHeight(5);
System.out.println(rectangle.getArea());
}
}

            
25

Rectangle 클래스와 다르게 Square 클래스는 가로 또는 세로의 길이가 변경될 때 하나의 속성만 변경하지 않고 둘 다 변경하게 됩니다. 이로 인해 동일한 결괏값이 아닌 25가 출력되었습니다. 즉, 리스코프 치환 원칙을 위배하게 됩니다.

 

LSP를 준수한 코드


다시 생각해 보면, 직사각형과 정사각형은 상속 관계로 연결될 수 없습니다. 이 둘은 모두 사각형의 일종으로, 서로의 특성을 일부 공유할 뿐 한쪽이 다른 쪽을 완전히 포함하는 구조가 아닙니다. 따라서 상위 개념인 사각형을 구현하고, 정사각형과 직사각형이 이를 상속받는 것이 더 올바른 접근입니다.


            
public class Shape {
private int width;
private int height;
public Shape(int width, int height) {
this.width = width;
this.height = height;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public int getArea() {
return width * height;
}
}

            
// 직사각형
class Rectangle extends Shape {
public Rectangle(int width, int height) {
super(width, height);
}
}
// 정사각형
class Square extends Shape {
public Square(int length) {
super(length, length);
}
}

위와 같이 Shape라는 사각형 클래스를 구현한 후, 사각형 클래스를 상속하여 정사각형과 직사각형을 구현합니다.

 

🤔 Setter 메서드는 LSP를 위배한다?

기존 코드와 달리, 인스턴스 생성 시에만 값을 할당하도록 Setter 메서드를 제외하였습니다. 이는 객체가 생성된 이후에도 Setter 메서드를 통해 상태를 변경할 수 있는 문제를 방지하기 위함입니다. LSP를 준수하려면, Setter 메서드를 사용하지 않는 것이 적절합니다.

 

LSP를 준수한다면 부모 클래스(Shape)와 자식 클래스(Rectangle, Square)들은 서로 교체가 되어도 기능이 같아야 합니다.


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

            
50
50
25
25

리스코프 치환 원칙에 따르면, 자식 객체는 부모 객체를 완전히 대체할 수 있어야 문제가 발생하지 않습니다. 직사각형과 정사각형의 경우처럼 잘못된 상속 관계를 제거하고, 부모 클래스의 동작을 완벽히 대체할 수 있는 관계만 상속하도록 설계해야 합니다. 

 

즉, 리스코프 치환 원칙을 준수하기 위해서는 부모 클래스의 일반 메서드가 그 의도와 다르게 오버라이딩되지 않도록 하는 것이 중요합니다.

 

'Spring > Spring Framework' 카테고리의 다른 글

인터페이스 분리 원칙(Interface Segregation Principle, ISP)  (0) 2024.07.03
단일 책임의 원칙(Single Responsibility Principle, SRP)  (0) 2024.06.27
개방 폐쇄 원칙(Open-Close Principle, OCP)  (0) 2024.06.26
의존성 역전 원칙(Dependency Inversion Principle, DIP)  (0) 2024.06.25
스프링(Spring)이란?  (0) 2024.02.03
  1. 리스코프 치환 원칙: Liskov Subsitution Principle
  2. 요구사항
  3. LSP를 준수하지 않은 코드
  4. LSP를 준수한 코드
'Spring/Spring Framework' 카테고리의 다른 글
  • 인터페이스 분리 원칙(Interface Segregation Principle, ISP)
  • 단일 책임의 원칙(Single Responsibility Principle, SRP)
  • 개방 폐쇄 원칙(Open-Close Principle, OCP)
  • 의존성 역전 원칙(Dependency Inversion Principle, DIP)
Hui._.
Hui._.
High hope
Hui._.
개발 일기
Hui._.
전체
오늘
어제
  • 분류 전체보기 (57)
    • Java (4)
    • Spring (26)
      • Spring Framework (6)
      • Spring Security (9)
      • JPA (11)
    • CS (2)
    • 알고리즘 (19)
      • 문제풀이 (16)
      • 자료구조 (3)
    • ETC (3)
    • Project (3)
      • Trouble Shooting (3)

블로그 메뉴

  • 홈
  • 글쓰기
  • 설정

공지사항

인기 글

태그

  • jwt
  • 유클리드
  • 회원 기능
  • SOLID
  • Spring Security 6.1
  • 스프링 시큐리티6.1
  • 분리
  • persist
  • 프로그래머스
  • 인터페이스
  • 추상화
  • 최대공약수
  • Spring Security
  • 최소공배수
  • 엔티티
  • 원칙
  • Oauth 2.0
  • Spring Security + JWT + OAuth 2.0
  • jpa
  • 호제법
  • 지연
  • 매핑
  • 스프링 부트3
  • 코딩테스트
  • java
  • oauth
  • dynamic programming
  • HashMap
  • Spring Boot 3.2.3
  • 알고리즘

최근 댓글

최근 글

hELLO · Designed By 정상우.v4.2.2
Hui._.
리스코프 치환 원칙(Liskov Subsitution Principle, LSP)
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.