State 패턴
이름 |
해설 |
State |
금고의 상태를 나타내는 인터페이스 |
DayState |
State를 구현하고 있는 클래스, 주간의 상태를 나타낸다. |
NightState |
State를 구현하고 있는 클래스, 야간의 상태를 나타낸다. |
Context |
금고의 상태변환를 관리하고 경비센터와 연락을 취하는 인터페이스 |
SafeFrame |
Context를 구현하는 클래스, 버튼이나 화면표시 등의 사용자인터페이스를 갖는다. |
Main |
동작 테스트용 클래스 |
State 인터페이스
package kch;
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);//일반통화
}
DayState 클래스
package kch;
public class DayState implements State {
private static DayState singleton = new DayState();
//주간 상태는 하나만 인스턴스를 만들기 위해서
//singleton 패턴을 씀.
//그래서 생성자는 private
private DayState(){
}
public static State getInstance(){//유일한 인스턴스를 얻는다.
return singleton;
}
@Override
public void doClock(Context context, int hour) {
// TODO Auto-generated method stub
if(hour < 9 || 17 <= hour){//이 시간때는 저녁시간이므로.
context.changeState(NightState.getInstance());//state를 바꾸기위해서 넘겨줌.
}
}
@Override
public void doUse(Context context) {
// TODO Auto-generated method stub
context.recordLog("금고사용(주간)");
}
@Override
public void doAlarm(Context context) {
// TODO Auto-generated method stub
context.callSecurityCenter("비상벨 (주간)");
}
@Override
public void doPhone(Context context) {
// TODO Auto-generated method stub
context.callSecurityCenter("일반통화(주간)");
}
public String toString(){
return "[주간]";
}
}
NightState 클래스
package kch;
public class NightState implements State{
private static NightState singleton = new NightState();
//인스턴스를 하나만 생성하기 위해서 singleton 패턴을 씀
//그래서 생성자는 private
private NightState(){
}
public static State getInstance(){//유일한 인스턴스를 얻는다.
return singleton;
}
@Override
public void doClock(Context context, int hour) {//시간설정
// TODO Auto-generated method stub
if(9 <= hour && hour < 17){//이시간대면 낮시간이므로 바꿔줌.
context.changeState(DayState.getInstance());
}
}
@Override
public void doUse(Context context) {//금고사용
// TODO Auto-generated method stub
context.callSecurityCenter("비상 : 야간금고 사용!");
}
@Override
public void doAlarm(Context context) {//비상벨
// TODO Auto-generated method stub
context.callSecurityCenter("비상벨 (야간)");
}
@Override
public void doPhone(Context context) {
// TODO Auto-generated method stub
context.recordLog("야간통화 녹음");
}
public String toString(){
return "[야간]";
}
}
Context 인터페이스
package kch;
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 클래스
package kch;
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();
show();
//listener의 설정
buttonUse.addActionListener(this);
buttonAlarm.addActionListener(this);
buttonPhone.addActionListener(this);
buttonExit.addActionListener(this);
}
//현재시간을 console창과 TextArea에 출력
@Override
public void setClock(int hour) {
// TODO Auto-generated method stub
String clockstring = "현재 시간은";
if(hour < 10){
clockstring += "0" + hour + ":00";
}else{
clockstring += hour + ":00";
}
System.out.println(clockstring);
textClock.setText(clockstring);//텍스트를 바꿔줌.
state.doClock(this, hour);//지금 시간과 SafeFrame 자신을 넘겨줌. 그래서 state를 바꿀지말지 결정
}
//상태 전환 현상태를 state로 전환함.
@Override
public void changeState(State state) {
// TODO Auto-generated method stub
System.out.println(this.state + "에서" + state + "로 상태가 변화했습니다.");
this.state = state;
}
@Override
public void callSecurityCenter(String msg) {
// TODO Auto-generated method stub
textScreen.append("call! " + msg + "\n" );
}
@Override
public void recordLog(String msg) {
// TODO Auto-generated method stub
textScreen.append("record .. " + msg + "\n");
}
//버튼이 눌려지면 이쪽으로 온다.
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
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("?");
}
}
}
Main 클래스
package kch;
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){
}
}
}//while문
}
}
낮과 밤이라는 상태를 분할을 해서 생각해보았습니다. 이렇게 생각을 안한다면
if(주간){
경비센터에 기록
}else if (야간){
경비센터에 비상사태 보고
}
이런식으로 if문을 써서 모든 경우의 수를 써야합니다. 상태가 2개가 아니라 수십개라면 이렇게 코딩하면 속도면이나 유지보수 측면에서 상당한 어려움을 겪을 것입니다.
이 코드의 핵심은 SafeFrame 클래스의 public void setClock(int hour) 부분이며
여기서 state.doClock(this, hour); 를 호출해서 지금 상태가 변해야되는지 말아야하는지를 결정합니다.
상태가 변해야된다면 context.changeState(NightState.getInstance()); 로 상태를 변화시킵니다.
'프로그래밍 > 자바 디자인패턴' 카테고리의 다른 글
디자인패턴 Interpreter 패턴 (0) | 2012.08.27 |
---|---|
디자인패턴 Command 패턴 (1) | 2012.08.18 |
디자인패턴 Proxy 패턴 (0) | 2012.08.16 |
디자인패턴 Flyweight 패턴 (0) | 2012.08.15 |
디자인 패턴 Memento 패턴 (0) | 2012.08.13 |
디자인패턴 Observer 패턴 (0) | 2012.08.10 |
디자인패턴 Mediator 패턴 (0) | 2012.08.09 |
디자인패턴 Facade 패턴 (0) | 2012.08.06 |