๐ก ์ํ(State) ํจํด์ด๋?
๊ฐ์ฒด์ ๋ด๋ถ ์ํ๊ฐ ๋ณ๊ฒฝ๋ ๋ ํด๋น ๊ฐ์ฒด๊ฐ ๊ทธ์ ํ๋์ ๋ณ๊ฒฝํ ์ ์๋๋ก ํ๋ ํ๋ ๋์์ธ ํจํด์ ๋๋ค. ๊ฐ์ฒด๊ฐ ํ๋์ ๋ณ๊ฒฝํ ๋ ๊ฐ์ฒด๊ฐ ํด๋์ค๋ฅผ ๋ณ๊ฒฝํ ๊ฒ์ฒ๋ผ ๋ณด์ผ ์ ์์ต๋๋ค. ์ฆ, ์ํ๋ฅผ ์กฐ๊ฑด๋ฌธ์ผ๋ก ๊ฒ์ฌํด์ ํ์๋ฅผ ๋ฌ๋ฆฌํ๋ ๊ฒ์ด ์๋, ์ํ๋ฅผ ๊ฐ์ฒดํ ํ์ฌ ์ํ๊ฐ ํ๋์ ํ ์ ์๋๋ก ์์ํ๋ ํจํด์ ๋งํฉ๋๋ค.
์ ๋ต ํจํด(Strategy Pattern)์ด '์ ๋ต ์๊ณ ๋ฆฌ์ฆ'์ ํด๋์ค๋ก ํํํ ํจํด์ด๋ผ๋ฉด, ์ํ ํจํด(State Pattern)์ '๊ฐ์ฒด ์ํ'๋ฅผ ํด๋์ค๋ก ํํํ ํจํด์ด๋ผ๊ณ ๋ณด๋ฉด ๋ฉ๋๋ค. ๋ฐ๋ผ์ ์ํ ํจํด์ ํด๋์ค ๋ค์ด์ด๊ทธ๋จ์ ๋ณด๋ฉด ์ ๋ต ํจํด๊ณผ ๋งค์ฐ ์ ์ฌํฉ๋๋ค. ๊ทธ๋ฌ๋, ์ํ ํจํด์์์ ํน์ ์ํ๋ค์ ์๋ก๋ฅผ ์ธ์ํ๊ณ ํ ์ํ์์ ๋ค๋ฅธ ์ํ๋ก ์ ์ด๋ฅผ ์์ํ ์ ์์ง๋ง ์ ๋ต๋ค์ ๊ฑฐ์ ๋๋ถ๋ถ ์๋ก์ ๋ํด ์์ง ๋ชปํ๋ค๋ ๊ฒ์ ๋๋ค.
๐ก ํด๋์ค ๋ค์ด์ด๊ทธ๋จ์ผ๋ก ๋ณธ ์ํ ํจํด
- Context : State๋ฅผ ์ด์ฉํ๋ ์์คํ ์ผ๋ก, ์์คํ ์ํ๋ฅผ ๋ํ๋ด๋ State ๊ฐ์ฒด๋ฅผ ํฉ์ฑ(composition)ํ์ฌ ๊ฐ์ง๊ณ ์์ต๋๋ค. ํด๋ผ์ด์ธํธ๋ก๋ถํฐ ์์ฒญ๋ฐ์ผ๋ฉด State ๊ฐ์ฒด์ ํ์ ์คํ์ ์์ํฉ๋๋ค.
- State Interface : ์ํ๋ฅผ ์ถ์ํํ ์ธํฐํ์ด์ค๋ก, ์ํ๋ณ ๋ฉ์๋๋ค์ ์ ์ธํฉ๋๋ค. State ์ญํ ๋ก ๊ฒฐ์ ๋๋ ์ธํฐํ์ด์ค(API)๋ฅผ ๊ตฌ์ฒด์ ์ผ๋ก ๊ตฌํํ๊ณ , ๋ค์ ์ํ๊ฐ ๊ฒฐ์ ๋๋ฉด Context์ ์ํ ๋ณ๊ฒฝ์ ์์ฒญํ๋ ์ญํ ๋ ํฉ๋๋ค.
- Concrete State : ์ํ๋ณ ๋ฉ์๋๋ค์ ๋ํ ์์ฒด์ ์ธ ๊ตฌํ์ ์ ๊ณตํฉ๋๋ค.
๐ก ์ํ ํจํด ๊ตฌํ
interface AbstractState {
void requestHandle(Context cxt);
}
class ConcreteStateA implements AbstractState {
@Override
public void requestHandle(Context cxt) {}
}
class ConcreteStateB implements AbstractState {
@Override
public void requestHandle(Context cxt) {
// ์ํ์์ ๋์์ ์คํํ ํ ๋ฐ๋ก ๋ค๋ฅธ ์ํ๋ก ๋ฐ๊พธ๊ธฐ๋ ํจ
// ์๋ฅผ ๋ค์ด ์ ์ on ์ํ์์ ๋๊ธฐ ๋์์ ์คํํํ ๊ฐ์ฒด ์ํ๋ฅผ ์ ์ off๋ก ๋ณ๊ฒฝ ํ๋ฏ์ด
cxt.setState(ConcreteStateC.getInstance());
}
}
class ConcreteStateC implements AbstractState {
@Override
public void requestHandle(Context cxt) {}
}
class Context {
AbstractState state; // composition
void setState(AbstractState state) {
this.state = state;
}
// ์ํ์ ์์กดํ ์ฒ๋ฆฌ ๋ฉ์๋๋ก์ state ๊ฐ์ฒด์ ์ฒ๋ฆฌ๋ฅผ ์์ํจ
void request() {
state.requestHandle(this);
}
}
class Client {
public static void main(String[] args) {
Context context = new Context();
// 1. StateA ์ํ ์ค์
context.setState(new ConcreteStateA());
// 2. ํ์ฌ StateA ์ํ์ ๋ง๋ ๋ฉ์๋ ์คํ
context.request();
// 3. StateB ์ํ ์ค์
context.setState(new ConcreteStateB());
// 4. StateB ์ํ์์ ๋๋ค๋ฅธ StateC ์ํ๋ก ๋ณ๊ฒฝ
context.request();
// 5. StateC ์ํ์ ๋ง๋ ๋ฉ์๋ ์คํ
context.request();
}
}
๐ก ๋ง๋ฌด๋ฆฌ
์ํ ํจํด์
- ๊ฐ์ฒด์ ํ๋(๋ฉ์๋)๊ฐ ์ํ(state)์ ๋ฐ๋ผ ๊ฐ๊ธฐ ๋ค๋ฅธ ๋์์ ํ ๋
- ์ํ๋ค์ ์๊ฐ ๋ง์ ๋
- ์ํ๋ณ ์ฝ๋๊ฐ ์์ฃผ ๋ณ๊ฒฝ๋ ๋
- ์ํ ๋ฐ ์ ํ์ ๊ฑธ์ณ ๋๊ท๋ชจ ์กฐ๊ฑด ๋ถ๊ธฐ ์ฝ๋์ ์ค๋ณต ์ฝ๋๊ฐ ๋ง์ ๋
- ๋ฐํ์์ ๊ฐ์ฒด์ ์ํ๋ฅผ ์ ๋์ ์ผ๋ก ๋ณ๊ฒฝํด์ผ ํ ๋
์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ํ ํจํด์ ์ฌ์ฉํ๋ฉด, ์ํ(State)์ ๋ฐ๋ฅธ ๋์์ ๊ฐ๋ณ ํด๋์ค๋ก ์ฎ๊ฒจ์ ๊ด๋ฆฌ ํ ์ ์๊ณ ,์ํ(State)์ ๊ด๋ จ๋ ๋ชจ๋ ๋์์ ๊ฐ๊ฐ์ ์ํ ํด๋์ค์ ๋ถ์ฐ์ํด์ผ๋ก์จ, ์ฝ๋ ๋ณต์ก๋๋ฅผ ์ค์ผ ์ ์์ต๋๋ค. ํน์ ์ํ์ ๊ด๋ จ๋ ์ฝ๋๋ฅผ ๋ณ๋์ ํด๋์ค๋ก ๊ตฌ์ฑํ๋ฏ๋ก SRP๋ฅผ ์ค์ํ๊ณ , ๊ธฐ์กด State ํด๋์ค๋ ์ปจํ ์คํธ๋ฅผ ๋ณ๊ฒฝํ์ง ์๊ณ ์ State๋ฅผ ๋์ ํ ์ ์์ผ๋ฏ๋ก OCP๋ฅผ ์ค์ํฉ๋๋ค.