2012-1
덕성여자대학교 정보미디어대학
교재: 자바언어로배우는디자인패턴입문(개정판)/YukiHiroshi저/김윤정역/영진닷컴
observer
– 관찰자
– 관찰 대상의 상태가 변하면, 관찰자에게 통지된다.
– 객체의 상태 변화에 따른 처리를 기술할 때 유용하게 사용된다.
관찰대상
관찰자1
관찰자2
1
관찰대상의 상태가 변하면 숫자 여러 개를 생성하는 객체를 관찰자가 관찰해서, 그 값 을 표시하는 프로그램
관찰자의 종류에 따라 표시 방법이 다르다
– DigitObserver: 값을 숫자로 표시함
– GraphObserver: 값을 간이 그래프로 표시함
:RandomNumberGenerator
:DigitObserver
:GraphObserver
관찰대상 관찰자
1) 관찰대상인 RandomNumberGenerator 객체가 난수를 하나 발생시킨 후, 2) 등록된 모든 관찰자의 update( ) 메소드를 호출해서 알려준다.
관찰자
클래스 다이어그램
관찰대상
관찰자
Observer 인터페이스
– 관찰자를 표현하는 인터페이스 – update(NumberGenerator)
NumberGenerator가 “나의 내용이 갱신되었습니다. 표시도 갱신 해주세요”라고 관찰자에게 알려줄 때 호출하는 메소드
NumberGenerator 클래스
– 수를 생성하는 클래스
– execute( ), getNumber( ): 추상 메소드
– observer 필드: NumberGenerator를 관찰하고 있는 Observer 들을 보관하고 있는 필드
– addObserver(Observer)
Observer를 추가할 때 호출하는 메소드
– deleteObserver(Observer)
Observer를 삭제할 때 호출하는 메소드
– notifyObservers( )
Observer 전원에게, “나의 내용이 갱신되었기 때문에 당신의 표시 도 갱신해주세요”라고 알려주는 메소드
Observer들의 update(this) 메소드를 차례차례 호출한다.
RandomNumberGenerator 클래스
– NumberGenerator의 하위 클래스 – 난수를 생성한다
java.util.Random 클래스 이용
– number 필드: 생성된 난수를 저장하는 변수 – getNumber( ): number 필드의 값을 반환함 – execute( ):
0~49 까지의 난수 20개를 생성하고, 그 때마다 notifyObservers 를 호출하여, 관찰자들에게 통지한다.
Random 클래스의 nextInt( ) 이용함
DigitObserver 클래스
– Observer 인터페이스를 구현한 구체적인 관찰자 – 관찰한 수를 ‘숫자’로 표시함
– update(NumberGenerator)
인자로 전달된 NumberGenerator의 getNmber( )를 이용하여 수 를 얻어서 화면에 출력한다.
출력한 후, 표시된 모습을 잘 알 수 있도록 Thread.sleep( )을 이용 하여 스피드를 늦춘다.
– Thread.sleep(100)
• (100/1000 = 0.1 초) 동안 CPU를 반환하고 쉬겠다는 뜻
GraphObserver 클래스
– Observer 인터페이스를 구현한 구체적인 관찰자 – 관찰한 수를 ‘간단한 그래프’로 표시함
관찰한 숫자만큼의 ‘*’를 출력한다
Main 클래스
– RandomNumberGenerator 인스턴스 1 개 생성함 – 관찰자 2개 생성함
– RandomNumberGenerator에 관찰자 2개를 등록함
– RandomNumberGenerator의 execute( )를 이용해서 수를 생 성한다
난수가 발생될 때마다, 관찰자들은 각자의 방식대로 수를 ‘표시’한 다.
Subject(관찰 대상자) 역할
– ‘관찰되는 쪽’을 나타냄
– Observer 역할을 등록하는 메소드와 삭제하는 메소드를 가진 다.
– 현재의 상태를 얻어갈 때 호출하는 메소드도 제공함 – 예제에서는, NumberGenerator 인터페이스가 해당됨
ConcreteSubject(구체적인 관찰대상자) 역할
– 구체적인 ‘관찰되는 쪽’을 나타냄
Observer(관찰자) 역할
– ‘관찰하는 쪽’을 나타냄
– Subject 역할로부터 상태변화를 통보받는 역할 – 예제에서는, Observer 인터페이스가 해당됨
통보받을 때, 관찰자의 update( ) 메소드가 호출됨
ConcreteObserver(구체적인 관찰자) 역할
– 구체적인 ‘관찰하는 쪽’을 나타냄
– 상태 변화가 관찰 대상으로부터 통보되면(즉, update 메소드가 호출되면) 그 메소드안에서 Subject 역할의 현재 상태를 얻어 서 적당한 일을 수행한다.
– 예제에서는, DigitObserver와 GraphObserver 클래스가 해당됨
여기서도 교환 가능성이 등장한다.
– RandomNumberGenerator 클래스는,
현재 자신을 관찰하고 있는 것이 DigitObserver의 인스턴스인지 GraphObserver의 인스턴스인지 모른다.
다만, 이들이 Observer 인터페이스를 구현하고 있다는 것만 안다.
– 한편, DigitObserver 클래스는,
자신이 관찰하고 있는 것이 RandomNumberGenerator의 인스턴 스인지 다른 XXXXXNumberGenerator의 인스턴스인지 신경쓰지 않는다.
다만, 관찰대상이 NumberGenerator의 하위 클래스의 인스턴스 이고 getNumber 메소드를 가지고 있다는 것만 알고 있다.
– 관찰자와 관찰 대상을 논리적으로 분리함으로써, 각각을 쉽게
교체할 수 있다 => 확장성/교환 가능성이 높아진다.
갱신을 위한 정보의 취급
– NumberGenerator는 update 메소드를 사용해서 ‘갱신되었습니다’라 고 Observer에게 통지한다.
이때, Observer 클래스의 update( )의 입력인자는 NumberGenerator 이다.
– Observer는 입력인자로 들어온 NumberGenerator를 이용하여 원하는 정보를 추출한다.
– NumberGenerator가, 관찰자가 필요한 정보만 넘겨줄 수도 있다.
void update(NumberGenerator generator){
... ...
//generator.getNumber() 이용 ... ...
}
subject(관찰대상)이,
‘관찰’하는 것이 아니고, 사실은 ‘통지’를 받는다.
– Observer의 역할이, 사실은 Subject로부터 통지가 오기를 기다리는, 수동적인 역할을 하고 있다.
– 그래서, Observer 패턴을 Publish-Subscribe 패턴이라고도 한다.
Model/View/Controller(MVC)
– Smalltalk 언어에서, 하나의 데이터 모델을 여러 형태로 보여 주고자 할 때 사용되는 유명한 패턴이다.
Subject A: 40 B: 25 C: 15
Observer 1 Observer 2
0 50
25
A B C D A
B C
D
모델
View
Mediator 패턴
객체의 상태변화를 다른 객체에게 통지하는 Observer 패턴
17-1
– 예제 프로그램에, 관찰대상으로서의
IncrementalNumberGenerator 클래스를 추가하기
시작하는 수와 마지막 수 및 증가분을 입력받는 생성자를 가진다.
– 예: new IncrementalNumberGenerator(10, 50, 5) 인 경우
• 10부터 50까지 5씩 증가하면서 숫자 생성 (10, 15, 20, ...) – 숫자가 만들어질 때 마다 관찰자에게 통지한다.
17-2
– 예제 프로그램에 새로운 관찰자 1개를 추가함
1. FrameObserver
– BorderLayout 매니저: 프레임 영역을 동서남북중앙으로 나눔 – update( ): GraphText와 GraphCanvas의 update( )를 호출함
FrameObserver GraphText
GraphCanvas 중앙
북
1.1 GraphText
– 숫자만큼의 ‘*’를 출력하는 관찰자
1.2. GraphCanvas
– Graphics 객체의 fillArc(int x, int y, int width, int height, int startAngle, int arcAngle)
• x, y, width, height: 원이 그려질 사각형 크기 지정
• startAngle 부터 arcAngle 만큼 그린다
• startAngle: 0 이면 3시 위치를 의미한다. (반시계방향으로 증가)
• arcAngle: 양수이면 반시계 방향으로 그리고, 음수이면 시계방향 으로 그린다
– 예: g.fillArc(0, 0, width, height, 90, -360* number/ 50);