2012-1
덕성여자대학교 정보미디어대학
교재: 자바언어로배우는디자인패턴입문(개정판)/YukiHiroshi저/김윤정역/영진닷컴
어떤 것을 클래스로 표현할지는 설계하는 사람의 마음이다.
클래스에 대응하는 구체적인 ‘사물’이 현실에 존재하는 경우 도 있고, 존재하지 않는 경우도 있다.
State 패턴은, ‘상태’를 클래스로 표현한 것이다.
– 클래스를 교체함으로써, ‘상태의 변화’를 나타낼 수 있고,
– 새로운 상태를 추가해야 할 때 무엇을 프로그램하면 되는지 명 확해진다.
금고경비 시스템
– 시각마다 경비의 상태가 변화는 금고경비 시스템 – 호출 상황을 화면에 표시한다.
– 프로그램상의 1초를 현실 세계의 1시간으로 가정한다.
3
State 패턴을 사용하지 않는 의사 코드 (pseudo code)
5 class 금고경비시스템 {
금고 사용시에 호출되는 메소드(){
if(주간) {
경비센터에 이용기록 } else if (야간) {
경비센터에 비상사태 통보 }
}
비상벨 사용시에 호출되는 메소드(){
경비센터에 비상벨의 통보 }
일반 통화시에 호출되는 메소드(){
if(주간) {
경비센터 호출 } else if (야간) {
경비센터의 자동응답기 호출 }
} }
State 패턴을 사용한 의사 코드(pseudo code)
– 앞의 코드와 달리, 파묻혀 있던 ‘상태’를 외부로 끌어냄
따라서, 상태를 체크하기 위한 if 문이 없다
주간이라는 상태를 표현한 클래스 { 금고 사용시에 호출되는 메소드(){
경비센터에 이용기록;
}
비상벨 사용시에 호출되는 메소드(){
경비센터에 비상벨의 통보;
}
일반 통화시에 호출되는 메소드(){
경비센터의 호출;
} }
야간이라는 상태를 표현한 클래스 { 금고 사용시에 호출되는 메소드(){
경비센터에 비상사태의 통보;
}
비상벨 사용시에 호출되는 메소드(){
경비센터에 비상벨의 통보;
}
일반 통화시에 호출되는 메소드(){
경비센터의 자동응답기 호출;
} }
7
State 인터페이스
– 금고의 상태를 나타냄
– 다음 이벤트가 발생했을 때 호출되는 인터페이스(API)를 제공
시각이 설정될 때 => doClock( )을 호출함
금고가 사용될 때 => doUse( )를 호출함
비상벨이 울릴 때 => doAlarm( )을 호출함
일반 통화를 할 때 => doPhone( )을 호출함
– 각 메소드의 형식 인자 Context
상태를 관리하거나 실제 경비센터를 호출하는 일을 하는 클래스
9
DayState 클래스
– 주간의 상태를 나타내는 클래스
– 하나의 상태만 필요하므로, Singleton 패턴을 사용함
DayState 타입의 객체를 static 으로 선언하고 인스턴스 한 개을 생성함
생성자를 private으로 선언함
– doClock( ): 시각을 설정하는 메소드
인자에서 제공된 시각이 야간의 시각이면, 시스템의 상태를 야간 으로 바꾼다.
– “주간 상태”에서 하는 일을 표현하는 메소드 (Context의 메소 드를 이용한다)
doUse( ): 주간에 금고를 사용했음을 기록
doAlarm( ): 비상벨로 경비센터를 호출함
doPhone( ): 경비센터에 일반통화를 함
NightState 클래스
– 야간의 상태를 나타내는 클래스 – DayState 클래스와 비슷하다.
11
Context 인터페이스
– 상태를 관리하거나 경비센터를 실제로 호출하는 클래스를 위 한 인터페이스를 제공한다.
13
(textScreen) BorderLayout
매니저
Button 객체들 Panel 객체
NORTH
CENTER
SOUTH
SafeFrame 클래스
– GUI를 사용해서, 금고경비 시스템을 실현한다.
– Context 인터페이스를 구현함
– state 필드: 금고의 현재 상태를 저장하는 변수
초기는 ‘주간’ 상태임
– 생성자에서 하는 일
배경색의 설정
레이아웃 매니저의 설정
부품의 배치
리스너(Listener)의 설정
– addActionListener 메소드를 이용하여 ActionListener를 구현한 객체 를 버튼에 등록한다.
– 버튼이 눌러지면 등록된 ActionListener 객체의 actionPerformed( ) 를 호출한다.
SafeFrame 클래스(계속)
– 버튼의 ActionListener는 SafeFrame 자신이다.
– actionPerformed( )
눌러진 버튼의 종류에 따라 state.doUse(this) / state.doAlarm(this) / state.doPhone(this) 중 하나를 호출한다.
현재 상태가 주간인지 야간이지 체크하는 코드가 필요없다.
– setClock( )
시간 설정을 위해서 클라이언트(Main)가 호출하는 메소드
– callSecurityCenter( )
경비센터에 대한 호출을 표현함
– recordLog( )
경비센터의 로그에 기록하는 일을 표현함
15
Main 클래스
– SafeFrame 인스턴스를 한 개 만든 후,
– 1초 간격으로 SafeFrame의 setClock( ) 메소드를 호출한다.
Thread.sleep(1000) 문장을 사용함.
“금고사용”버튼이 눌려진 후에 doUse( )를 실행하는 모습
17
주간에서 야간으로 바뀐다.
State(상태)의 역할
– 상태를 나타내는 역할
– 각 상태에 따라 다른 행동을 하는 통일된 인터페이스(API)를 결정함
– 예제에서는, State 인터페이스가 해당됨
ConcreteState(구체적인 상태)의 역할 – 구체적인 개개의 상태를 표현하는 역할 – State 역할이 결정한 인터페이스를 구현함
– 예제에서는, DayState와 NightState 클래스가 해당됨
Context(상황, 전후관계, 문맥)의 역할
– 현재의 상태를 나타내는 ConcreteState 역할을 가지고 있음 – State 패턴 이용자가 필요로 하는 인터페이스를 결정함
– 예제에서는 Context 인터페이스와 SafeFrame 클래스가 해당 됨.
19
분할해서 통치하라
– “divide and conquer”
복잡하고 규모가 큰 프로그램을 다룰 때, 우선 작은 문제로 나누 어라. 그래도 풀기 어려우면 더 작은 문제로 나누어라.
– State 패턴에서는
개개의 구체적인 상태를 각각 클래스로 나누어서 표현함으로써 문제를 분할함
– 상태의 종류가 많을수록 유용함
State 패턴을 사용하지 않는다면, 계속해서 상태를 검사하는 조건 문이 필요하다.
예: 상태가 10가지라면, if-else-if 문이 10개 정도 필요함
상태에 의존한 처리
– Main 클래스가 SafeFrame의 setClock( ) 메소드를 호출해서 시 각을 설정해달라고 부탁함
– setClock( ) 메소드 안에서는, state.doClock(this, hour)를 호출 하여 현재 state에 그 처리를 위임함
– 현재 state가 무엇이냐에 따라 행동이 달라진다. 즉, “상태에 따 라 행동이 달라지는 처리”이다.
21
새로운 상태를 추가하는 것은 간단
– 예제 프로그램에서는, State 인터페이스를 구현한 XXXState 클 래스를 만들어 필요한 메소드를 구현하기만 하면 된다.
STD(State Transition Diagram)
– 시스템의 상태 변화를 표현하기 위해 많이 사용되는 다이어그램
금고의 상태 변화를 State Transition Diagram으로 표현해 보면...
23
DayState NightState
hour < 9 || 17 <= hour
9 <= hour && hour < 17
Singleton 패턴
Flyweight 패턴
시스템의 각 상태를 클래스로 표현한 State 패턴
25
19-1
– Context 인터페이스를 추상 클래스로 정의하지 않은 이유는?
다중 상속과 관련이 있음
19-2
– 주간, 야간 범위를 변경하는 경우, 코드 수정은 어떻게 해야 하는가?
19-3
– “점심시간” 이라는 상태를 추가하시오.
19-4
– “비상시”라는 상태를 추가하시오.