Java 디자인 패턴-07.State
(Java 디자인 패턴 스터디 모집 중 : https://github.com/bluedskim/javaDesignPatterns)
패턴 다이어그램
“어떤 객체의 상태에 따라 행위가 변경되는 경우 유용한 패턴”
(출처:https://refactoring.guru/design-patterns/state)
해결하려는 문제
- context의 상태에 따른 처리가 구분되는 경우 해당 구분로직을 context에 하드 코딩하게 되면 경우 확장성이 떨어진다.
특징/용도
- 상태를 클래스화 하고 해당 동작들을 넣는다
- 원래의 객체(context)는 현재 상태 객체의 참조를 가진다
- context는 2개 이상의 상태를 동시에 가질 수는 없다
고려사항
- State 패턴은 Strategy 패턴과 유사하다. 주요한 차이점은 상태객체들은 서로의 존재를 아는 반면 Strategy패턴에서는 Strategy간의 관련성은 없다는 것이다(https://refactoring.guru/design-patterns/state)
클래스 다이어그램
소스
- Context : 상태를 가지고있는 객체(Package.java)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
package net.dskim.desingpattern.state.solution;
/**
* 주문 객체
*/
public class Package {
private PackageState currentState = new OrderedState();
public void setState(PackageState newState) {
this.currentState = newState;
}
public PackageState getState() {
return this.currentState;
}
/**
* 상태 변경시 알려줄 대상 목록 반환
* @return
*/
public String getNotifyGetterList() {
return currentState.getNotifyGetterList();
}
}
|
- State
- OrderedState.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
package net.dskim.desingpattern.state.solution;
/**
* 상태 객체-주문
*/
public class OrderedState implements PackageState {
/**
* 알림 수신 대상자 목록 반환
*/
@Override
public String getNotifyGetterList() {
return "shipper";
}
@Override
public String toString() {
return "OrderedState";
}
}
|
- DelieveredState.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
package net.dskim.desingpattern.state.solution;
/**
* 상태 객체-배송완료
*/
public class DeliveredState implements PackageState {
/**
* 알림 수신 대상자 목록 반환
*/
@Override
public String getNotifyGetterList() {
return "orderer";
}
@Override
public String toString() {
return "DeliveredState";
}
}
|
- ReceivedState.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
package net.dskim.desingpattern.state.solution;
/**
* 상태 객체-수령완료
*/
public class ReceivedState implements PackageState {
/**
* 알림 수신 대상자 목록 반환
*/
@Override
public String getNotifyGetterList() {
return "orderer,manager";
}
@Override
public String toString() {
return "ReceivedState";
}
}
|
- client : StateTest.java
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
26
27
28
29
30
31
32
33
|
package net.dskim.desingpattern.state.solution;
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class StateTest {
@Test
void stateTest() {
Package pkg = new Package();
log.info("state={}", pkg.getState());
assertEquals("shipper", pkg.getNotifyGetterList());
pkg.setState(new DeliveredState());
log.info("state={}", pkg.getState());
assertEquals("orderer", pkg.getNotifyGetterList());
pkg.setState(new ReceivedState());
log.info("state={}", pkg.getState());
assertEquals("orderer,manager", pkg.getNotifyGetterList());
/* //CancelState를 추가하는 경우에도 Package 소스를 수정할 필요가 없다
pkg.setState(new CancelState());
log.info("state={}", pkg.getState());
assertEquals("shipper,manager", pkg.getNotifyGetterList());
*/
}
}
|
참고