Post

⛓️ Java Design-Pattern XX - State

⛓️ Java Design-Pattern XX - State

πŸ“— γ€ŽJAVA μ–Έμ–΄λ‘œ λ°°μš°λŠ” λ””μžμΈ νŒ¨ν„΄ : μ‰½κ²Œ λ°°μš°λŠ” GoF의 23κ°€μ§€ λ””μžμΈ νŒ¨ν„΄γ€λ₯Ό 읽고 μ •λ¦¬ν•œ κΈ€μž…λ‹ˆλ‹€.

State νŒ¨ν„΄μ΄λž€?

  • Javaμ—μ„œ 객체 μ§€ν–₯ ν”„λ‘œκ·Έλž˜λ°μ„ ν•  λ•Œ ν”„λ‘œκ·Έλž˜λ° λŒ€μƒμ„ 클래슀둜 ν‘œν˜„ν•œλ‹€.
  • State νŒ¨ν„΄μ—μ„œλŠ” μƒνƒœλ₯Ό 클래슀둜 ν‘œν˜„ν•œλ‹€.
  • μƒνƒœλ₯Ό 클래슀둜 ν‘œν˜„ν•˜λ©΄ 클래슀λ₯Ό μ „ν™˜ν•¨μœΌλ‘œμ¨ μƒνƒœ λ³€ν™”λ₯Ό λ‚˜νƒ€λ‚Ό 수 있으며, μƒˆλ‘œμš΄ μƒνƒœλ₯Ό μΆ”κ°€ν•΄μ•Ό ν•  λ•Œ 무엇을 ν”„λ‘œκ·Έλž˜λ° ν• μ§€ λͺ…ν™•ν•΄μ§„λ‹€.

예제 ν”„λ‘œκ·Έλž¨

  • λ‹€μŒμ€ 금고 κ²½λΉ„ μ‹œμŠ€ν…œμ„ 예제 ν”„λ‘œκ·Έλž¨μœΌλ‘œ λ§Œλ“  것이닀.

  • ν”„λ‘œκ·Έλž¨ μƒμ˜ 1초λ₯Ό ν˜„μ‹€ μ„Έκ³„μ˜ 1μ‹œκ°„μœΌλ‘œ κ°€μ •ν•œλ‹€.
  • κΈˆκ³ κ°€ ν•˜λ‚˜ μžˆλ‹€.
  • κΈˆκ³ λŠ” κ²½λΉ„ 센터와 μ—°κ²°λ˜μ–΄ μžˆλ‹€.
  • κΈˆκ³ μ—λŠ” 비상벨과 일반 ν†΅ν™”μš© μ „ν™”κ°€ μ—°κ²°λ˜μ–΄ μžˆλ‹€.
  • κΈˆκ³ μ—λŠ” μ‹œκ³„κ°€ μ„€μΉ˜λ˜μ–΄ μžˆμ–΄, ν˜„μž¬ μ‹œκ°μ„ κ°μ‹œν•œλ‹€.
  • 주간은 9:00 ~ 16:59, 야간은 17:00 ~ 23:59 및 0:00 ~ 8:59 λ²”μœ„μ΄λ‹€.
  • κΈˆκ³ λŠ” μ£Όκ°„μ—λ§Œ μ‚¬μš©ν•  수 μžˆλ‹€.
  • 주간에 금고λ₯Ό μ‚¬μš©ν•˜λ©΄ κ²½λΉ„ 센터에 비상벨 톡보가 κ°„λ‹€.
  • 일반 ν†΅ν™”μš© μ „ν™”λŠ” μ–Έμ œλΌλ„ μ‚¬μš©ν•  수 μžˆλ‹€.(단, 야간은 λ…ΉμŒλ§Œ κ°€λŠ₯)
  • 주간에 μ „ν™”λ₯Ό μ‚¬μš©ν•˜λ©΄ κ²½λΉ„ μ„Όν„°κ°€ ν˜ΈμΆœλœλ‹€.
  • 야간에 μ „ν™”λ₯Ό μ‚¬μš©ν•˜λ©΄ κ²½λΉ„ μ„Όν„°μ˜ μžλ™ 응닡기가 ν˜ΈμΆœλœλ‹€.

State νŒ¨ν„΄μ„ μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” μ˜μ‚¬ μ½”λ“œ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
κ²½λΉ„ μ‹œμŠ€ν…œ 클래슀 {
	금고 μ‚¬μš© μ‹œ ν˜ΈμΆœλ˜λŠ” λ©”μ„œλ“œ() {
		if (μ£Όκ°„) {
			κ²½λΉ„ 센터에 μ‚¬μš© 기둝
		} else if (μ•Όκ°„) {
			κ²½λΉ„ 센터에 비상 상황 기둝
		}
	}
	
	비상벨 μ‚¬μš© μ‹œ ν˜ΈμΆœλ˜λŠ” λ©”μ„œλ“œ() {
		κ²½λΉ„ 센터에 비상벨 톡보
	}
	
	일반 톡화 μ‹œ ν˜ΈμΆœλ˜λŠ” λ©”μ„œλ“œ() {
		if (μ£Όκ°„) {
			κ²½λΉ„ μ„Όν„° 호좜
		} else if (μ•Όκ°„) {
			κ²½λΉ„ μ„Όν„° μžλ™ 응닡기 호좜
		}
	}
}

State νŒ¨ν„΄μ„ μ‚¬μš©ν•œ μ˜μ‚¬ μ½”λ“œ

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
μ£Όκ°„ μƒνƒœλ₯Ό ν‘œμ‹œν•˜λŠ” 클래슀 {
	금고 μ‚¬μš© μ‹œ ν˜ΈμΆœλ˜λŠ” λ©”μ„œλ“œ() {
		κ²½λΉ„ 센터에 μ‚¬μš© 기둝
	}
	
	비상벨 μ‚¬μš© μ‹œ ν˜ΈμΆœλ˜λŠ” λ©”μ„œλ“œ() {
		κ²½λΉ„ 센터에 비상벨 톡보
	}
	
	일반 톡화 μ‹œ ν˜ΈμΆœλ˜λŠ” λ©”μ„œλ“œ() {
		κ²½λΉ„ μ„Όν„° 호좜
	}
}

μ•Όκ°„ μƒνƒœλ₯Ό ν‘œμ‹œν•˜λŠ” 클래슀 {
	금고 μ‚¬μš© μ‹œ ν˜ΈμΆœλ˜λŠ” λ©”μ„œλ“œ() {
		κ²½λΉ„ 센터에 비상 상황 기둝
	}
	
	비상벨 μ‚¬μš© μ‹œ ν˜ΈμΆœλ˜λŠ” λ©”μ„œλ“œ() {
		κ²½λΉ„ 센터에 비상벨 톡보
	}
	
	일반 톡화 μ‹œ ν˜ΈμΆœλ˜λŠ” λ©”μ„œλ“œ() {
		κ²½λΉ„ μ„Όν„° μžλ™ 응닡기 호좜
	}
}
  • State νŒ¨ν„΄μ„ μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” μ˜μ‚¬ μ½”λ“œμ—μ„œλŠ” μ£Όκ°„, μ•Όκ°„μ΄λΌλŠ” μƒνƒœκ°€ 각 λ©”μ„œλ“œμ˜ ifλ¬Έ 뢀뢄에 λ“±μž₯ν•œλ‹€.
  • 반면 State νŒ¨ν„΄μ„ μ‚¬μš©ν•˜λŠ” μ˜μ‚¬ μ½”λ“œμ—μ„œλŠ” μƒνƒœκ°€ 클래슀둜 ν‘œν˜„λ˜μ—ˆκΈ° λ•Œλ¬Έμ—, 각 λ©”μ„œλ“œμ—λŠ” ν˜„μž¬ μƒνƒœλ₯Ό μ²΄ν¬ν•˜λŠ” if문이 λ“±μž₯ν•˜μ§€ μ•ŠλŠ”λ‹€.

State μΈν„°νŽ˜μ΄μŠ€

1
2
3
4
5
6
public interface State {
	public abstract void doClock(Context context, int hour);
	public abstract void doUse(Context context);
	public abstract void doAlarm(Context context);
	public abstract void doPhone(Context context);
}
  • 금고 μƒνƒœλ₯Ό λ‚˜νƒ€λ‚΄λŠ” μΈν„°νŽ˜μ΄μŠ€λ‹€.
  • μ‹œκ°„μ΄ μ„€μ •λ˜μ—ˆμ„ λ•Œ, κΈˆκ³ κ°€ μ‚¬μš©λ˜μ—ˆμ„ λ•Œ, 비상벨이 λˆŒλ Έμ„ λ•Œ, 일반 톡화λ₯Ό ν•  λ•Œ ν˜ΈμΆœλœλ‹€.
  • 인수둜 μ „λ‹¬λ˜λŠ” ContextλŠ” μƒνƒœλ₯Ό κ΄€λ¦¬ν•˜λŠ” μΈν„°νŽ˜μ΄μŠ€λ‹€.

DayState 클래슀

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
34
35
public class DayState implements State {
	private static DayState singleton = new DayState();
	private DayState() { }
	
	public static State getInstance() {
		return singleton;
	}
	
	@Override
	public void doClock(Context context, int hour) {
		if (hour < 9 || 17 <= hour) {
			context.changeState(NightState.getInstance());
		}
	}
	
	@Override
	public void doUse(Context context) {
		context.recordLog("κΈˆκ³ μ‚¬μš©(μ£Όκ°„)");
	}
	
	@Override
	public void doAlarm(Context context) {
		context.callSecurityCenter("비상벨(μ£Όκ°„)");
	}
	
	@Override
	public void doPhone(Context context) {
		context.callSecurityCenter("μΌλ°˜ν†΅ν™”(μ£Όκ°„)");
	}
	
	@Override
	public String toString() {
		return "[μ£Όκ°„]";
	}
}
  • μ£Όκ°„ μƒνƒœλ₯Ό λ‚˜νƒ€λ‚΄λŠ” 클래슀둜, State μΈν„°νŽ˜μ΄μŠ€μ—μ„œ μ„ μ–Έλœ λ©”μ„œλ“œλ₯Ό κ΅¬ν˜„ν•œλ‹€.
  • μƒνƒœλ₯Ό λ‚˜νƒ€λ‚΄λŠ” ν΄λž˜μŠ€λŠ” μΈμŠ€ν„΄μŠ€λ₯Ό ν•˜λ‚˜μ”©λ§Œ λ§Œλ“ λ‹€.
  • μƒνƒœκ°€ λ³€ν™”ν•  λ•Œλ§ˆλ‹€ μΈμŠ€ν„΄μŠ€λ₯Ό λ§Œλ“€λ©΄ λ©”λͺ¨λ¦¬μ™€ μ‹œκ°„μ΄ λ‚­λΉ„λ˜κΈ° λ•Œλ¬Έμ΄λ‹€.
  • κ·Έ λ•Œλ¬Έμ— Singleton νŒ¨ν„΄μ„ μ‚¬μš©ν•œλ‹€.
  • doClock() λ©”μ„œλ“œλŠ” μ£Όμ–΄μ§„ μ‹œκ°„μ΄ 야간이면 μ•Όκ°„ μƒνƒœλ‘œ μ‹œμŠ€ν…œμ„ μ „ν™˜ν•œλ‹€.
  • doUse(), doAlarm(), doPhone() λ©”μ„œλ“œλŠ” 각각 금고 μ‚¬μš©, 비상벨, 일반 ν†΅ν™”λΌλŠ” 사건에 λŒ€μ‘ν•œλ‹€.
  • 이듀 λ©”μ„œλ“œ μ•ˆμ— ν˜„μž¬ μƒνƒœλ₯Ό μ²΄ν¬ν•˜λŠ” if문은 μ‘΄μž¬ν•˜μ§€ μ•ŠλŠ”λ‹€.
  • 이렇듯 State νŒ¨ν„΄μ—μ„œλŠ” μƒνƒœμ˜ 차이가 클래슀의 차이둜 λ‚˜νƒ€λ‚˜λ―€λ‘œ if, switch λ“± μƒνƒœ λ³„λ‘œ λΆ„κΈ°ν•  ν•„μš”κ°€ μ—†λ‹€.

NightState 클래슀

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
34
35
36
public class NightState implements State {
	private static NightState singleton = new NightState();
	
	private NightState() { }
	
	public static State getInstance() {
		return singleton;
	}
	
	@Override
	public void doClock(Context context, int hour) {
		if (9 <= hour && hour < 17) {
			context.changeState(DayState.getInstance());
		}
	}
	
	@Override
	public void doUse(Context context) {
		context.callSecurityCenter("λΉ„μƒοΌšμ•Όκ°„ 금고 μ‚¬μš©οΌ");
	}
	
	@Override
	public void doAlarm(Context context) {
		context.callSecurityCenter("비상벨(μ•Όκ°„)");
	}
	
	@Override
	public void doPhone(Context context) {
		context.recordLog("μ•Όκ°„ 톡화 λ…ΉμŒ");
	}
	
	@Override
	public String toString() {
		return "[μ•Όκ°„]";
	}
}
  • μ•Όκ°„ μƒνƒœλ₯Ό λ‚˜νƒ€λ‚΄λŠ” 클래슀둜, State μΈν„°νŽ˜μ΄μŠ€μ—μ„œ μ„ μ–Έλœ λ©”μ„œλ“œλ₯Ό κ΅¬ν˜„ν•œλ‹€.
  • 이 클래슀 λ˜ν•œ Singleton νŒ¨ν„΄μ„ μ‚¬μš©ν•œλ‹€.

Context μΈν„°νŽ˜μ΄μŠ€

1
2
3
4
5
6
public interface Context {
	public abstract void setClock(int hour);             // μ‹œκ°„ μ„€μ •
	public abstract void changeState(State state);       // μƒνƒœ λ³€ν™”
	public abstract void callSecurityCenter(String msg); // κ²½λΉ„ μ„Όν„° 경비원 호좜
	public abstract void recordLog(String msg);          // κ²½λΉ„ μ„Όν„° 기둝
}
  • μƒνƒœλ₯Ό κ΄€λ¦¬ν•˜κ±°λ‚˜ κ²½λΉ„ μ„Όν„°λ₯Ό ν˜ΈμΆœν•œλ‹€.

SafeFrame 클래슀

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Frame;
import java.awt.Panel;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class SafeFrame extends Frame implements ActionListener, Context {
	private TextField textClock = new TextField(60);      // ν˜„μž¬ μ‹œκ°„ ν‘œμ‹œ
	private TextArea textScreen = new TextArea(10, 60);   // κ²½λΉ„ μ„Όν„° 좜λ ₯
	private Button buttonUse = new Button("금고 μ‚¬μš©");    // 금고 μ‚¬μš© λ²„νŠΌ
	private Button buttonAlarm = new Button("비상벨");     // 비상벨 λ²„νŠΌ
	private Button buttonPhone = new Button("일반 톡화");  // 일반 톡화 λ²„νŠΌ
	private Button buttonExit = new Button("μ’…λ£Œ");       // μ’…λ£Œ λ²„νŠΌ
	private State state = DayState.getInstance();        // ν˜„μž¬ μƒνƒœ
	
	/* μƒμ„±μž */
	public SafeFrame(String title) {
		super(title);
		setBackground(Color.lightGray);
		setLayout(new BorderLayout());
		
		// textClock 배치
		add(textClock, BorderLayout.NORTH);
		textClock.setEditable(false);
		
		// textScreen 배치
		add(textScreen, BorderLayout.CENTER);
		textScreen.setEditable(false);
		
		// νŒ¨λ„μ— λ²„νŠΌ μ €μž₯
		Panel panel = new Panel();
		panel.add(buttonUse);
		panel.add(buttonAlarm);
		panel.add(buttonPhone);
		panel.add(buttonExit);
		
		// κ·Έ νŒ¨λ„μ„ 배치
		add(panel, BorderLayout.SOUTH);
		
		// ν‘œμ‹œ
		pack();
		setVisible(true);
		
		// λ¦¬μŠ€λ„ˆ μ„€μ •
		buttonUse.addActionListener(this);
		buttonAlarm.addActionListener(this);
		buttonPhone.addActionListener(this);
		buttonExit.addActionListener(this);
	}
	
	/* λ²„νŠΌμ΄ 눌리면 μ—¬κΈ°λ‘œ μ˜¨λ‹€ */
	@Override
	public void actionPerformed(ActionEvent e) {
		System.out.println(e.toString());
		if (e.getSource() == buttonUse) {           // 금고 μ‚¬μš© λ²„νŠΌ
			state.doUse(this);
		} else if (e.getSource() == buttonAlarm) {  // 비상벨 λ²„νŠΌ
			state.doAlarm(this);
		} else if (e.getSource() == buttonPhone) {  // 일반 톡화 λ²„νŠΌ Β 
			state.doPhone(this);
		} else if (e.getSource() == buttonExit) {   // μ’…λ£Œ λ²„νŠΌ
			System.exit(0);
		} else {
			System.out.println("?");
		}
	}
	
	/* μ‹œκ°„ μ„€μ • */
	@Override
	public void setClock(int hour) {
		String clockstring = String.format("ν˜„μž¬ μ‹œκ°„μ€ %02d:00", hour);
		System.out.println(clockstring);
		textClock.setText(clockstring);
		state.doClock(this, hour);
	}
	
	/* μƒνƒœ λ³€ν™” */
	@Override
	public void changeState(State state) {
		System.out.println(this.state + "μ—μ„œ" + state + "으둜 μƒνƒœκ°€ λ³€ν™”ν–ˆμŠ΅λ‹ˆλ‹€.");
		this.state = state;
	}
	
	/* κ²½λΉ„ μ„Όν„° 경비원 호좜 */
	@Override
	public void callSecurityCenter(String msg) {
		textScreen.append("call! " + msg + "\n");
	}
	
	/* κ²½λΉ„ μ„Όν„° 기둝 */
	@Override
	public void recordLog(String msg) {
		textScreen.append("record ... " + msg + "\n");
	}
}
  • Context μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜μ—¬ GUIλ₯Ό 톡해 금고 κ²½λΉ„ μ‹œμŠ€ν…œμ„ μ‹€ν˜„ν•œλ‹€.
  • SafeFrame 클래슀의 ν•„λ“œλŠ” 화면에 ν‘œμ‹œλ˜λŠ” ν…μŠ€νŠΈ ν•„λ“œλ‚˜ ν…μŠ€νŠΈ μ˜μ—­, λ²„νŠΌ λ“±μ˜ λΆ€ν’ˆμ΄λ‹€.
  • 단 state ν•„λ“œλŠ” ν™”λ©΄ 상 λΆ€ν’ˆμ΄ μ•„λ‹Œ 금고의 ν˜„μž¬ μƒνƒœλ₯Ό λ‚˜νƒ€λ‚Έλ‹€.
  • μƒμ„±μžμ—μ„œλŠ” λ‹€μŒκ³Ό 같은 처리λ₯Ό ν•œλ‹€.
  1. 배경색 μ„€μ •
  2. λ ˆμ΄μ•„μ›ƒ κ΄€λ¦¬μž μ„€μ •
  3. λΆ€ν’ˆ 배치
  4. λ¦¬μŠ€λ„ˆ μ„€μ •
  • 각 λ²„νŠΌμ˜ addActionListener() λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜μ—¬ λ¦¬μŠ€λ„ˆλ₯Ό μ„€μ •ν•œλ‹€.
  • 이 λ•Œ ν•΄λ‹Ή λ©”μ„œλ“œμ˜ 인수둜 λ²„νŠΌμ„ λˆŒλ €μ„ λ•Œ 호좜될 μΈμŠ€ν„΄μŠ€λ₯Ό κ²°μ •ν•œλ‹€.
  • λ˜ν•œ ν•΄λ‹Ή μΈμŠ€ν„΄μŠ€λŠ” ActionListener μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•΄μ•Ό ν•œλ‹€.
  • λ²„νŠΌμ„ λˆŒλ €μ„ λ•Œ λ¦¬μŠ€λ„ˆκ°€ ν˜ΈμΆœλ˜λŠ” κ΅¬μ‘°λŠ” Observer νŒ¨ν„΄κ³Ό μœ μ‚¬ν•˜λ‹€.
  • ActionPerformed() λ©”μ„œλ“œλŠ” λ²„νŠΌμ„ λˆŒλ €μ„ λ•Œ ν˜ΈμΆœλ˜λŠ” λ©”μ„œλ“œμ΄λ‹€.
  • 이 λ©”μ„œλ“œ λͺ…은 java.awt.event.ActionListener μΈν„°νŽ˜μ΄μŠ€μ—μ„œ μ •ν•΄μ§„ μ΄λ¦„μ΄λ―€λ‘œ ν•¨λΆ€λ‘œ μˆ˜μ •ν•΄μ„œλŠ” μ•ˆλœλ‹€.
  • 이 ν΄λž˜μŠ€μ— if문이 λ“±μž₯ν•˜μ§€λ§Œ, λ²„νŠΌ μ’…λ₯˜μ— λŒ€μ‘ν•˜λŠ” 것이지 ν˜„μž¬ μƒνƒœμ— λŒ€μ‘ν•˜λŠ” 것이 μ•„λ‹˜μ„ μ£Όμ˜ν•΄μ•Ό ν•œλ‹€.
  • κ°€λ Ή 금고 μ‚¬μš© λ²„νŠΌμ„ λˆ„λ₯΄λ©΄ state.doUse(this) λ©”μ„œλ“œκ°€ μ‹€ν–‰λœλ‹€.
  • State νŒ¨ν„΄μ„ μ‚¬μš©ν•˜κΈ° λ•Œλ¬Έμ— ν˜„μž¬ μ‹œκ°μ΄λ‚˜ ν˜„μž¬ 금고 μƒνƒœλ₯Ό μ‘°μ‚¬ν•˜λŠ” λΆ„κΈ° μ²˜λ¦¬κ°€ λΆˆν•„μš”ν•˜λ‹€.
  • setClock() λ©”μ„œλ“œλŠ” μ‹œκ°„μ„ ν‘œμ‹œν•˜κ³ , μ‹œκ°„μ— λŒ€ν•œ μƒνƒœλ₯Ό μ„€μ •ν•œλ‹€.
  • changeState() λ©”μ„œλ“œλŠ” DayState λ˜λŠ” NightState ν΄λž˜μŠ€μ—μ„œ ν˜ΈμΆœλœλ‹€.
  • callSecurityCenter() λ©”μ„œλ“œλŠ” κ²½λΉ„ μ„Όν„° ν˜ΈμΆœμ„ λ‚˜νƒ€λ‚΄λ©° recordLog λ©”μ„œλ“œλŠ” κ²½λΉ„ μ„Όν„°μ˜ 기둝을 λ‚˜νƒ€λ‚Έλ‹€.

Main 클래슀

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Main {
	public static void main(String[] args) {
		SafeFrame frame = new SafeFrame("State Sample");
		while (true) {
			for (int hour = 0; hour < 24; hour++) {
				frame.setClock(hour); // μ‹œκ°„ μ„€μ •
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) { }
			}
		}
	}
}
  • SafeFrame μΈμŠ€ν„΄μŠ€λ₯Ό ν•˜λ‚˜ λ§Œλ“€κ³ , κ·Έ μΈμŠ€ν„΄μŠ€μ— λŒ€ν•΄ μ •κΈ°μ μœΌλ‘œ μ‹œκ°„μ„ μ„€μ •ν•œλ‹€.
  • μ‹œκ°„ 섀정은 1μ΄ˆλ§ˆλ‹€ μ΄λ€„μ§€λŠ”λ°, ν”„λ‘œκ·Έλž¨ μ•ˆμ—μ„œλŠ” 1μ‹œκ°„μ— ν•΄λ‹Ήν•œλ‹€.

State νŒ¨ν„΄μ˜ λ“±μž₯인물

State μΈν„°νŽ˜μ΄μŠ€

  • μƒνƒœλ§ˆλ‹€ λ‹€λ₯΄κ²Œ λ™μž‘ν•˜λŠ” μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ •μ˜ν•œλ‹€.
  • 이 μΈν„°νŽ˜μ΄μŠ€λŠ” μƒνƒœμ— μ˜μ‘΄ν•œ λ©”μ„œλ“œ λͺ¨μŒμ΄ λœλ‹€.
  • μƒνƒœλ₯Ό λ‚˜νƒ€λ‚΄λŠ” μƒνƒœ(State) 역을 λ§‘μ•˜λ‹€.

DayState, NightState 클래슀

  • ꡬ체적인 각각의 μƒνƒœλ₯Ό λ‚˜νƒ€λ‚Έλ‹€.
  • Stateμ—μ„œ μ •μ˜λœ μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•˜λŠ” ꡬ체적인 μƒνƒœ(ConcreteState) 역을 λ§‘μ•˜λ‹€.

Context μΈν„°νŽ˜μ΄μŠ€, SafeFrame 클래슀

  • State νŒ¨ν„΄ μ‚¬μš©μžμ—κ²Œ ν•„μš”ν•œ μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ •μ˜ν•˜λŠ” λ¬Έλ§₯(Context) 역을 λ§‘μ•˜λ‹€.
  • Context μΈν„°νŽ˜μ΄μŠ€κ°€ μΈν„°νŽ˜μ΄μŠ€λ₯Ό μ •μ˜ν•˜κ³  SafeFrame ν΄λž˜μŠ€κ°€ ConcreteStateλ₯Ό κ°€μ§€λŠ” 뢀뢄을 λ§‘μ•˜λ‹€.

μ±…μ—μ„œ μ œμ‹œν•˜λŠ” 힌트

λΆ„ν• ν•΄μ„œ ν†΅μΉ˜ν•˜λΌ.

  • 크고 λ³΅μž‘ν•œ 문제λ₯Ό κ·ΈλŒ€λ‘œ ν•΄κ²°ν•˜λ € ν•΄μ„  μ•ˆλœλ‹€.
  • μž‘μ€ 문제둜 λ‚˜λˆ„κ³ , κ·Έλž˜λ„ νž˜λ“€λ‹€λ©΄ 더 μž‘κ²Œ λ‚˜λˆ μ•Ό ν•œλ‹€.
  • κ°„λ‹¨νžˆ λ§ν•˜λ©΄, λΆ„ν• ν•΄μ„œ ν†΅μΉ˜ν•˜λΌλŠ” 말은 κΉŒλ‹€λ‘œμš΄ 문제λ₯Ό ν•˜λ‚˜ ν‘ΈλŠ” λŒ€μ‹  μž‘κ³  μ‰¬μš΄ 문제λ₯Ό 많이 ν’€λΌλŠ” 말이닀.
  • State νŒ¨ν„΄μ—μ„œλŠ” μƒνƒœλ₯Ό 클래슀둜 ν‘œν˜„ν•˜λŠ”λ°, 각각의 ꡬ체적인 μƒνƒœλ₯Ό 클래슀둜 ν‘œν˜„ν•΄μ„œ 문제λ₯Ό λΆ„ν• ν•œ 것이닀.
  • μƒνƒœκ°€ λ§Žμ•„μ§ˆμˆ˜λ‘ ν•΄λ‹Ή νŒ¨ν„΄μ€ 빛을 λ°œν•œλ‹€.
  • μ•žμ„œ μ†Œκ°œν•œ μ˜μ‚¬ μ½”λ“œμ—μ„œ, State νŒ¨ν„΄μ„ μ‚¬μš©ν•˜μ§€ μ•Šμ„ 경우 ν˜„μž¬ μƒνƒœμ— λŒ€μ‘ν•œ 쑰건 λΆ„κΈ°κ°€ λ°œμƒν•˜λŠ” 것을 μ•Œ 수 μžˆλ‹€.
  • μƒνƒœκ°€ λ§Žμ•„μ§ˆμˆ˜λ‘ 이 쑰건 뢄기도 λŠ˜μ–΄λ‚˜κΈ° λ•Œλ¬Έμ— ν”„λ‘œκ·Έλž¨μ˜ λ³΅μž‘μ„±μ΄ μ¦κ°€ν•œλ‹€.

μƒνƒœμ— μ˜μ‘΄ν•œ 처리

  • SafeFrame 클래슀의 setClock() λ©”μ„œλ“œλŠ” Main ν΄λž˜μŠ€μ—μ„œ ν˜ΈμΆœλœλ‹€.
  • ν•΄λ‹Ή λ©”μ„œλ“œλ₯Ό 톡해 μ‹œκ°„ 섀정을 μ§€μ‹œν•˜κ³  setClock() λ©”μ„œλ“œ λ‚΄λΆ€μ—μ„œλŠ” λ‹€μŒκ³Ό 같이 state에 μœ„μž„ν•œλ‹€.
1
state.doClock(this, hour);
  • 즉, μ‹œκ°„ 섀정을 ν˜„μž¬ μƒνƒœμ— μ˜μ‘΄ν•˜λŠ” 처리둜 닀룬닀.
  • doClock뿐만 μ•„λ‹ˆλΌ State μΈν„°νŽ˜μ΄μŠ€μ— μ •μ˜λœ λ©”μ„œλ“œλŠ” λͺ¨λ‘ μƒνƒœμ— 따라 λ™μž‘μ΄ λ‹¬λΌμ§€λŠ” μ²˜λ¦¬λ‹€.
  • State νŒ¨ν„΄μ—μ„œλŠ” μƒνƒœμ— μ˜μ‘΄ν•˜λŠ” 처리λ₯Ό ν”„λ‘œκ·Έλž¨μœΌλ‘œ λ‹€μŒκ³Ό 같이 ν‘œν˜„ν•œλ‹€.
  1. 좔상 λ©”μ„œλ“œλ‘œ μ„ μ–Έν•˜κ³  μΈν„°νŽ˜μ΄μŠ€λ‘œ ν•œλ‹€.
  2. ꡬ상 λ©”μ„œλ“œλ‘œ κ΅¬ν˜„ν•˜κ³  κ°œλ³„ 클래슀둜 ν•œλ‹€.

μƒνƒœ μ „ν™˜μ€ λˆ„κ°€ 관리해야 ν•˜λŠ”κ°€?

  • 예제 ν”„λ‘œκ·Έλž¨μ—μ„œλŠ” Context 역을 맑은 SafeFrame ν΄λž˜μŠ€κ°€ μ‹€μ œλ‘œ μƒνƒœλ₯Ό μ „ν™˜ν•˜λŠ” changeState() λ©”μ„œλ“œλ₯Ό κ΅¬ν˜„ν–ˆλ‹€.
  • ν•΄λ‹Ή λ©”μ„œλ“œλ₯Ό μ‹€μ œλ‘œ ν˜ΈμΆœν•˜λŠ” 것은 DayState λ˜λŠ” NightState ν΄λž˜μŠ€μ΄λ‹€.
  • 즉, 예제 ν”„λ‘œκ·Έλž¨μ—μ„œλŠ” μƒνƒœ μ „ν™˜μ„ μƒνƒœμ— μ˜μ‘΄ν•˜λŠ” λ™μž‘μœΌλ‘œ μƒκ°ν•œλ‹€.
  • 이 λ°©μ‹μ—λŠ” μž₯단점이 각각 μ‘΄μž¬ν•œλ‹€.
  • μž₯점은 λ‹€λ₯Έ μƒνƒœλ‘œ μ „ν™˜ν•˜λŠ” μ‹œμ μ— λŒ€ν•œ 정보가 ν•œ 클래슀 내에 μžˆλ‹€λŠ” 점이닀.
  • 예λ₯Ό λ“€μ–΄ DayState ν΄λž˜μŠ€κ°€ μ–Έμ œ λ‹€λ₯Έ μƒνƒœλ‘œ μ „ν™˜ν•˜λŠ” μ§€ μ•Œκ³  μ‹Άλ‹€λ©΄ λ‹¨μˆœνžˆ ν•΄λ‹Ή 클래슀의 μ½”λ“œλ₯Ό 읽으면 λœλ‹€.
  • 단점은 ν•œ ꡬ체적인 μƒνƒœ 역이 λ‹€λ₯Έ ꡬ체적인 μƒνƒœ 역을 μ•Œμ•„μ•Ό ν•œλ‹€λŠ” 점이닀.
  • κ°€λ Ή DayState ν΄λž˜μŠ€μ—μ„œλŠ” doClock() λ©”μ„œλ“œ μ•ˆμ—μ„œ NightState μΈμŠ€ν„΄μŠ€λ₯Ό μ‚¬μš©ν•œλ‹€.
  • 즉, λ‚˜μ€‘μ— NightState 클래슀λ₯Ό μ‚­μ œν•˜κ²Œ λœλ‹€λ©΄ DayState ν΄λž˜μŠ€λ„ μˆ˜μ •ν•΄μ•Ό ν•œλ‹€.
  • μ΄λŸ¬ν•œ 점은 클래슀 μ‚¬μ΄μ˜ 의쑴 관계λ₯Ό 깊게 λ§Œλ“€μ–΄ 버린닀.
  • 예제 ν”„λ‘œκ·Έλž¨κ³Ό 같은 방식을 κ·Έλ§Œλ‘κ³  λͺ¨λ“  μƒνƒœ μ „ν™˜μ„ Context μ—­μ˜ SafeFrame ν΄λž˜μŠ€μ— λ§‘κΈΈ μˆ˜λ„ μžˆλ‹€.
  • κ·Έλ ‡κ²Œ ν•œλ‹€λ©΄ κ°œλ³„ ꡬ체적인 μƒνƒœ μ—­μ˜ 독립성이 μ’‹μ•„μ Έμ„œ 전체 ν”„λ‘œκ·Έλž¨μ˜ 전망이 ν–₯μƒλ˜λŠ” κ²½μš°κ°€ μžˆλ‹€.
  • λ˜λŠ” State νŒ¨ν„΄ λŒ€μ‹  μƒνƒœ ν…Œμ΄λΈ”μ„ μ‚¬μš©ν•˜μ—¬ 섀계할 μˆ˜λ„ μžˆλ‹€.
  • ν…Œμ΄λΈ”μ€ μž…λ ₯κ³Ό λ‚΄λΆ€ μƒνƒœλ₯Ό λ°”νƒ•μœΌλ‘œ 좜λ ₯κ³Ό λ‹€μŒ λ‚΄λΆ€ μƒνƒœλ₯Ό 얻을 수 μžˆλŠ” μ•Œλ¦Όν‘œκ°€ λœλ‹€.
  • μƒνƒœ 변경이 κ³ μ •λœ κ·œμΉ™μ— 바탕을 λ‘” κ²½μš°μ—λŠ” 이처럼 ν…Œμ΄λΈ”μ„ μ‚¬μš©ν•˜λŠ” ν”„λ‘œκ·Έλž¨λ„ 효과적이라고 ν•  수 μžˆλ‹€.
  • μƒνƒœ μˆ˜κ°€ λ§Žμ€ κ²½μš°μ—λŠ” μˆ˜μž‘μ—…μ„ ν¬κΈ°ν•˜κ³ , ν”„λ‘œκ·Έλž¨μ„ μžλ™μœΌλ‘œ μƒμ„±ν•˜λŠ” λ‹€λ₯Έ ν”„λ‘œκ·Έλž¨μ„ μ‚¬μš©ν•˜λŠ” 방법도 μžˆλ‹€.

자기 λͺ¨μˆœμ— λΉ μ§€μ§€ μ•ŠλŠ”λ‹€.

  • State νŒ¨ν„΄μ„ μ‚¬μš©ν•˜μ§€ μ•Šκ³  μ‹œμŠ€ν…œ μƒνƒœκ°€ μ—¬λŸ¬ λ³€μˆ«κ°’μ˜ μ§‘ν•©μœΌλ‘œ ν‘œν˜„λ˜μ–΄ μžˆλ‹€κ³  κ°€μ •ν•΄λ³΄μž.
  • μ΄λ•Œ λ³€μˆ«κ°’ μ‚¬μ΄μ˜ 자기 λͺ¨μˆœμ΄λ‚˜ λΆˆμΌμΉ˜κ°€ μ—†μ–΄μ•Ό ν•œλ‹€.
  • State νŒ¨ν„΄μ—μ„œλŠ” μƒνƒœλ₯Ό 클래슀둜 ν‘œν˜„ν•˜κ³ , ν˜„μž¬ μƒνƒœλ₯Ό ν‘œν˜„ν•˜λŠ” λ³€μˆ˜λŠ” 단 ν•˜λ‚˜μ΄λ‹€.
  • κ·Έλ ‡κΈ° λ•Œλ¬Έμ— ν•΄λ‹Ή λ³€μˆ˜κ°€ μ‹œμŠ€ν…œμ˜ μƒνƒœλ₯Ό ν™•μ‹€νžˆ κ²°μ •ν•˜λ―€λ‘œ 자기 λͺ¨μˆœμ„ λ‚΄ν¬ν•œ μƒνƒœλΌλŠ” 것이 μ‘΄μž¬ν•˜μ§€ μ•Šκ²Œ λœλ‹€.

μƒˆλ‘œμš΄ μƒνƒœλ₯Ό μΆ”κ°€ν•˜λŠ” 것은 κ°„λ‹¨ν•˜λ‹€.

  • 예제 ν”„λ‘œκ·Έλž¨μœΌλ‘œ 예λ₯Ό λ“€λ©΄, State μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•œ XxxState 클래슀λ₯Ό λ§Œλ“€κ³ , ν•„μš”ν•œ λ©”μ„œλ“œλ₯Ό κ΅¬ν˜„ν•˜λ©΄ λœλ‹€.
  • λ¬Όλ‘  μƒνƒœ μ „ν™˜ 뢀뢄은 λ‹€λ₯Έ ꡬ체적인 μƒνƒœ μ—­κ³Όμ˜ 접점이 λ˜λ―€λ‘œ μ£Όμ˜ν•΄μ„œ κ΅¬ν˜„ν•΄μ•Ό ν•œλ‹€.
  • 반면 μ™„μ„±λœ State νŒ¨ν„΄μ— μƒˆλ‘œμš΄ μƒνƒœ 의쑴 처리λ₯Ό κ΅¬ν˜„ν•˜λŠ” 것은 μ–΄λ ΅λ‹€.
  • State μ—­μ˜ μΈν„°νŽ˜μ΄μŠ€μ— λ©”μ„œλ“œλ₯Ό μΆ”κ°€ν•˜λŠ” 것을 μ˜λ―Έν•˜λŠ”λ°, λͺ¨λ“  ꡬ체적인 μƒνƒœ 역에 처리λ₯Ό μΆ”κ°€ν•΄μ•Ό ν•˜κΈ° λ•Œλ¬Έμ΄λ‹€.
  • λ¬Όλ‘  λ©”μ„œλ“œλ₯Ό μΆ”κ°€ν•˜μ§€ μ•ŠμœΌλ©΄ μ»΄νŒŒμΌν•  λ•Œ λ©”μ„œλ“œκ°€ κ΅¬ν˜„λ˜μ§€ μ•Šμ•˜μŒμ„ 였λ₯˜λ‘œ μ•Œλ €μ£ΌκΈ° λ•Œλ¬Έμ— λˆ„λ½λ  μœ„ν—˜μ€ μ—†λ‹€.
  • 만일 State νŒ¨ν„΄μ„ μ‚¬μš©ν•˜μ§€ μ•ŠλŠ”λ‹€λ©΄, μƒνƒœλ₯Ό νŒλ‹¨ν•˜λŠ” 것은 ifλ¬Έ μ•ˆμ˜ 쑰건식이기 λ•Œλ¬Έμ—, 였λ₯˜λ₯Ό μ»΄νŒŒμΌν•  λ•Œ κ²€μΆœν•˜κΈ° μ–΄λ ΅λ‹€.
  • 참고둜 κ³ λ €ν•˜μ§€ μ•Šμ€ μƒνƒœλ₯Ό κ²€μΆœν•˜λ©΄ 였λ₯˜λ‘œ μ²˜λ¦¬ν•˜λ©΄ 되기 λ•Œλ¬Έμ— μ‹€ν–‰ν•  λ•Œ κ²€μΆœν•˜λŠ” 것은 μ–΄λ ΅μ§€ μ•Šλ‹€.

두 얼꡴을 κ°€μ§„ μΈν„°νŽ˜μ΄μŠ€

  • SafeFrame ν΄λž˜μŠ€μ— λ“±μž₯ν•œ λ‹€μŒ 두 μ½”λ“œλ₯Ό μ‚΄νŽ΄λ³΄μž.
1
2
3
4
5
/* μƒμ„±μž μ•ˆ */
buttonUse.addActionListner(this);

/* actionPerformed μ•ˆ */
state.doUse(this);
  • 예제 ν”„λ‘œκ·Έλž¨μ—μ„œλŠ” SafeFrame μΈμŠ€ν„΄μŠ€κ°€ ν•˜λ‚˜λ§Œ μƒμ„±λ˜λ―€λ‘œ thisκ°€ λ™μΌν•˜μ§€λ§Œ, addActionListner()에 전달될 λ•Œμ™€ doUse()에 전달될 λ•ŒλŠ” 쑰금 차이가 μžˆλ‹€.
  • addActionListner()에 전달될 λ•ŒλŠ” ActionListener μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•œ 클래슀의 μΈμŠ€ν„΄μŠ€λ‘œμ„œ 닀루어진닀.
  • 인수둜 μ „λ‹¬λœ 것이 SafeFrame μΈμŠ€ν„΄μŠ€μΈμ§€ μ—¬λΆ€λŠ” μ€‘μš”ν•˜μ§€ μ•Šλ‹€.
  • doUse()에 전달될 λ•ŒλŠ” λ™μΌν•œ μΈμŠ€ν„΄μŠ€κ°€ Context μΈν„°νŽ˜μ΄μŠ€λ₯Ό κ΅¬ν˜„ν•œ 클래슀의 μΈμŠ€ν„΄μŠ€λ‘œ 닀루어진닀.
  • doUse() λ©”μ„œλ“œ μ•ˆμ—μ„œλŠ” Context μΈν„°νŽ˜μ΄μŠ€μ—μ„œ μ •μ˜λœ λ©”μ„œλ“œ λ²”μœ„μ—μ„œ μΈμˆ˜κ°€ μ΄μš©λœλ‹€.
  • λ™μΌν•œ ν•˜λ‚˜μ˜ μΈμŠ€ν„΄μŠ€μ— μ—¬λŸ¬ 얼꡴이 μžˆλ‹€λŠ” 점을 κΈ°μ–΅ν•˜μž.
This post is licensed under CC BY 4.0 by the author.