Java

[Design Pattern] 상태 패턴(State Pattern)

구루싸 2020. 7. 20. 23:12
반응형
SMALL

오랜만에 글을 작성하네요-_-

태안에 조개잡이를 떠났다가

여자친구가 모기에

50방을 물렸네요-_-

모기에게 100% 물리지 않는

어떤 약이나 도구가

발명된다면 대박일듯...

아무튼 이번 학습 주제는

상태(State) 패턴입니다

객체 지향 프로그래밍에서는

프로그램 할 대상을

클래스(Class)로 표현하고

이것을 설계해야합니다

오늘 학습할 상태 패턴은

상태를 클래스로

표현하는 패턴입니다

그럼 상태 패턴의

역할들을 정리하고

시작하겠습니다

역할 설명
State(상태) 상태를 나타내며 상태가 변할 때마다 다른 동작을 하는 인터페이스를 결정
Concrete State(구체적인 상태) 구체적인 각각의 상태를 표현하고 State 역할로 결정되는 인터페이스를 구체적으로 구현
Context(문맥) 현재의 상태를 나타내는 Concrete State 역할을 가지며 State 패턴의 이용자에게 필요한 인터페이스를 결정

역할 정리만으로는

이해하기가 어렵네요-_-

구현해보겠습니다

1. 인터페이스(Interface) State.java

package statePattern;

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);
}

2. 클래스(Class) DayState.java

package statePattern;

public class DayState implements State {
	private static DayState singleton = new DayState();
	private DayState() {
	}
	public static State getInstance() {
		return singleton;
	}
	public void doClock(Context context, int hour) {
		if ( hour < 9 || 17 <= hour ) {
			context.changeState(NightState.getInstance());
		}
	}
	public void doUse(Context context) {
		context.recordLog("금고사용(주간)");
	}
	public void doAlarm(Context context) {
		context.callSecurityCenter("비상벨(주간)");
	}
	public void doPhone(Context context) {
		context.callSecurityCenter("일반통화(주간)");
	}
	public String toString() {
		return "[주간]";
	}
}

3. 클래스(Class) NightState.java

package statePattern;

public class NightState implements State {
	private static NightState singleton = new NightState();
	private NightState() {
	}
	public static State getInstance() {
		return singleton;
	}
	public void doClock(Context context, int hour) {
		if ( hour >= 9 && 17 > hour ) {
			context.changeState(DayState.getInstance());
		}
	}
	public void doUse(Context context) {
		context.recordLog("비상 : 야간금고 사용!");
	}
	public void doAlarm(Context context) {
		context.callSecurityCenter("비상벨(야간)");
	}
	public void doPhone(Context context) {
		context.callSecurityCenter("야간통화 녹음");
	}
	public String toString() {
		return "[야간]";
	}
}

4. 인터페이스(Interface) Context.java

package statePattern;

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);
}

5. 클래스(Class) SafeFrame.java

package statePattern;
import java.awt.*;
import java.awt.event.*;
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());
		add(textClock, BorderLayout.NORTH);
		textClock.setEditable(false);
		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();
		show();
		buttonUse.addActionListener(this);
		buttonAlarm.addActionListener(this);
		buttonPhone.addActionListener(this);
		buttonExit.addActionListener(this);
	}
	
	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("?");
		}
	}
	
	public void setClock(int hour) {
		String clockstring = "현재 시간은";
		if ( hour < 10 ) {
			clockstring += "0" + hour + ":00";
		} else {
			clockstring += hour + ":00";
		}
		System.out.println(clockstring);
		textClock.setText(clockstring);
		state.doClock(this, hour);
	}
	
	public void changeState(State state) {
		System.out.println(this.state + "에서" + state + "로 상태가 변화했습니다.");
		this.state = state;
	}
	
	public void callSecurityCenter(String msg) {
		textScreen.append("call! " + msg + "\n");
	}
	
	public void recordLog(String msg) {
		textScreen.append("record ... " + msg + "\n");
	}
}

6. 클래스(Class) Test.java

import statePattern.*;
public class Test {
	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 ) {
				}
			}
		}
	}
}

위의 코드에서

DayState와 LightState를

싱글톤(Singleton) 패턴으로

구현하고 있습니다

싱글톤 패턴에 대해

궁금하시다면

아래의 링크로 ↓

2020/06/14 - [Java] - [Design Pattern] 싱글톤(Singleton) 패턴과 프로토타입(Prototype) 패턴

 

[Design Pattern] 싱글톤(Singleton) 패턴과 프로토타입(Prototype) 패턴

어느 덧 한 주를 마무리하는 일요일이 되었습니다 내일이 되면 다시 한주를 바쁘게 살아가야한다는... 아무튼 오늘은 지정한 클래스의 인스턴스가 한 개만 존재하는 것을 보증하고 싶을 때 사용

yssa.tistory.com

상태 패턴은

상태를 클래스로 표현해서

복잡한 프로그램을 분할하며

이느 Divide & Conquer 방침을

이행하고 있습니다

그런데 이 패턴은

상태전환을 Concrete State 역할

(DayState, LightState)이 하며

이것은 둘의 의존도를 높이는

단점이 있습니다

이번 학습은

여기서 마치고

다음 학습 주제는

플라이급(Flyweight)

패턴에 대해 알아보겠습니다

그럼 이만-_-

 

 

반응형
LIST