우아한테크코스/level1
리스코프 치환원칙
무비인
2022. 3. 19. 21:44
리스코프 치환원칙은 상속에 대해 공부하다가 알게 되었다.
개념
부모 클래스의 인스턴스를 사용하는 위치에 자식 클래스의 인스턴스를 대신 사용했을 때,
코드가 원래 의도대로 작동해야한다.
리모컨 예제
1
2
3
4
5
6
7
8
9
10
11
12
13
|
class 리모컨 {
boolean power;
void 켜기(){
power = true;
}
void 끄기(){
power = false;
}
}
|
cs |
이제 이걸 상속받은 TV 리모컨
, 에어컨 리모컨
이 있다고 하자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
class Tv_리모컨 extends 리모컨 {
boolean power;
void 켜기(){
power = true;
}
void 끄기(){
power = false;
}
void 채널 돌리기(){}
}
|
cs |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
class 에어컨_리모컨 extends 리모컨 {
boolean power;
void 켜기(){
power = true;
}
void 끄기(){
power = false;
}
void 온도_올리기(){}
void 온도_낮추기(){}
}
|
cs |
위 두개는 부모 클래스인 리모컨이 제공하는 기능을 제공하면서 추가로 다른 기능을 제공하고 있다.
따라서 리스코프 치환원칙을 잘 지켰다고 할 수 있다.
못 지켰을 때는 언제일까?
자식 클래스에서 잘못된 오버라이딩을 할 때
현재 메서드 명만 봤을 때 에어컨의 리모컨은 기계의 전원을 켜고, 끄는 것 처럼 보인다.
그런데 실제동작은 켜기를 눌렀을 때 꺼지고, 꺼짐을 눌렀을 때 켜지도록 오버라이딩 되었다.
이는 부모 클래스가 의도한 기능을 제공했다고 볼 수 없기 때문에 리스코프 치환원칙에 위배 된다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
class 에어컨_리모컨 extends 리모컨 {
boolean power;
int 온도;
@Override
void 켜기(){
power = false
}
@Override
void 끄기(){
power = true;
}
void 온도 올리기(){
온도 = 온도+1;
}
void 온도 낮추기(){
온도 = 온도-1;
}
}
|
cs |
자식 클래스에서 추가된 변수를 사용하여 오버라이딩을 할 때
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
class 에어컨_리모컨 extends 리모컨 {
boolean power;
int 온도;
@Override
void 켜기(){
power = false;
온도 = 10;
}
@Override
void 끄기(){
power = true;
온도 = 0;
}
void 온도 올리기(){
온도 = 온도+1;
}
void 온도 낮추기(){
온도 = 온도-1;
}
}
|
cs |
왜 리스코프 치환원칙을 지켜야하는가?
1) 유지보수성을 위해
리스코프 치환원칙을 위배한다고 해서 시스템 상 에러가 발생하지 않는다.
그래서 더 위험하다. 프로그램 작성자가 다른 사람이 위 켜기 메서드를 볼 때
켜기를 눌렀는데 온도가 조절 될 것이라 생각이 들겠는가?
따라서 이상 동작이 어디서 시작 된 것인지 파악하기 어려워진다. 의도 된 동작만 하게끔 리스코프 치환원칙을 지키자.