'상태'를 클래스로 표현하는 패턴
: 객체의 내부 상태가 변경될 때 해당 객체가 그의 행동을 변경할 수 있도록 한다
일반적으로 객체의 상태에 따라 적절한 행동들을 선택하는 많은 조건문(if 또는 switch)으로 구현된다
class Document is
field state: string
// …
method publish() is
switch (state)
"draft":
state = "moderation"
break
"moderation":
if (currentUser.role == "admin")
state = "published"
break
"published":
// Do nothing.
break
// …
: 시간마다 경비 상태가 변화하는 금고경비 시스템
금고는 1개
금고는 경비센터와 연결되어 있다
금고에는 비상벨과 일반통화용 전화가 연결되어 있다.
금고에는 시계가 설치되어 있어 현재의 시간을 감시
주간은 09:00~16:59
, 야간은 17:00~23:59
및 0:00~8:59
금고는 주간에만 사용 가능
주간에 금고를 사용하면 경비센터에 사용기록이 남는다
야간에 금고를 사용하면 경비센터에 비상사태로 통보가 간다
비상벨은 언제나 사용가능
비상벨을 사용하면 경비센터에 비상벨 통보가 된다
일반통화용의 전화는 언제나 사용가능(야간은 녹음만 가능)
주간에 전화를 사용하면 경비센터가 호출됩니다.
야간에 전화를 사용하면 경비센터의 자동응답기가 호출됩니다.
경비시스템클래스 {
금고사용시_호출_메소드() {
if(주간){
경비센터에_이용_기록
} else if (야간) {
경비센터에_비상사태_통보
}
}
비상벨_사용시_호출_메소드() {
경비센터에_비상벨_통보
}
일반_통화시_호출_메소드() {
if (주간) {
경비센터의_호출
} else if (야간) {
경비센터의_자동응답기_호출
}
}
}
이름 | 설명 |
---|---|
State | 금고의 상태를 나타내는 인터페이스 |
DayState | State를 구현하고 있는 클래스, 주간의 상태를 나타낸다. |
NightState | State를 구현하고 있는 클래스. 야간의 상태를 나타낸다. |
Context | 금고의 상태변환을 관리하고 경비센터와 연락을 취하는 인터페이스 |
SafeFrame | Context를 구현하는 클래스, 버튼이나 화면표시 등의 사용자 인터페이스를 갖는다. |
Main | 동작 테스트용 클래스 |
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); // 일반 통화
}
public class DayState implements State{
private static DayState singletone = new DayState(); // 주간 상태 인스턴스 생성
public DayState() {
}
public static State getInstance() {
return singletone;
}
@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("일반통화(주간)");
}
public String toString() {
return "[주간]";
}
}
public class NightState implements State{
private static NightState singletone = new NightState();
public NightState() {
}
public static State getInstance() {
return singletone;
}
@Override
public void doClock(Context context, int hour) {
if (9 <= hour && hour < 17) { // 주간의 경우
context.changeState(DayState.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("야간통화 녹음");
}
public String toString() {
return "[야간]";
}
}
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);
}
public class SafeFrame extends Frame implements ActionListener, Context {
private final TextField textClock = new TextField(60);
private final TextArea textScreen = new TextArea(10, 60);
private final Button buttonUse = new Button("금고사용");
private final Button buttonAlarm = new Button("비상벨");
private final Button buttonPhone = new Button("일반통화");
private final Button buttonExit = new Button("종료");
private State state = DayState.getInstance();
public SafeFrame(String title) throws HeadlessException {
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);
}
//Event Listener Handler
public void actionPerformed(ActionEvent event) {
System.out.println(event.toString());
if (event.getSource() == buttonUse) {
state.doUse(this); // 금고 사용
} else if (event.getSource() == buttonAlarm) {
state.doAlarm(this);
} else if (event.getSource() == buttonPhone) {
state.doPhone(this);
} else if (event.getSource() == buttonExit) {
System.exit(0);
} else {
System.out.println("?");
}
}
@Override
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);
}
//상태전환
@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");
}
}
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){
}
}
}
}
}