Observer Pattern : 객체들간 관계 중에 특정 객체의 상태 변화에 대해 실시간으로 반응해야 하는 객체가 있다. 이런 객체들의 상태변화를 관찰하기 위한 방법에 대해 쉽게 생각한다면 일정 시간마다 관찰 대상의 상태를 점검하여 반응하도록 할 수 있을것이다. 하지만 대상의 상태가 변하지 않았는데도 주기적으로 관찰해야한다면 프로그래밍적인 관점에서 그리 좋은 밥법이라고는 할 수 없다. 하드웨어 인터럽트가 있는것 처럼, 관찰 대상이 변했을때 "나 변했소!" 라고 알려준다면 불필요한 관찰행동을 없애며 상태의 변화에 따라 민감하게 반응할 수 있을것이다. 이러한 행위를 구조화 한 것이 Observer pattern이다.
관찰자(Observer)의 관점에서 구현을 고려한다면 처음 생각해 보았던 방법(일정 주기마다 관찰 대상 체크)뿐이 답일것이다. 하지만 관찰 대상(Observable)의 관점에서 고려한다면, 그리고 관찰 대상이 성실한 관찰대상이라고 가정할 수 있다면 관찰자는 불필요한 에너지 낭비를 크게 줄일 수 있을것이다. Observer pattern은 이와같이 관찰 대상의 관점에서 고안된 패턴이라고 할 수 있다.
관찰 대상들은 누가 자신을 관찰하는지 관찰자들의 목록을 가지고있으며, 관찰 대상이 늘어나면 그 관찰 대상에게 자신을 좀 봐달라고 알리게된다(Observable.attach). 반대로 관찰자가 더이상 관찰하지 않는다면 관찰 대상은 자신의 관찰자 목록에서 그를 빼버린다(Observable.detach). 그리고 중요한 부분으로 관찰 대상 자신의 상태가 변하여 자신을 봐주길 원한다면 관찰자들에게 그 사실을 알리며(Observable.notify), 관찰자들은 정신을 차리고 대상의 상태를 반영한다. 즉, 관찰자와 관찰대상이 N:1의 관계를 가지는 것이다.
게임 캐릭터중에 소환사 한명이 있다. 소환사의 크리쳐들은 똑똑하게도 소환사의 상태에따라 행동을 달리한다. 소환사가 관찰 대상이며 크리쳐들이 관찰자가된다. 이를 예제로 들어보자.
/* Summorner.java */
public class Summorner implements Observable{
private int hp;
private ArrayList<Observer> creatures;
public Summorner(){
hp = 100;
creatures = new ArrayList<Observer>();
}
public void attach(Observer newCreature){
creatures.add(newCreature);
}
public void detach(Observer delCreature){
creatures.remove(delCreature);
}
public void notify(){
for(Observer o : creatures){
o.update( ((Object)this.hp) );
}
}
public void setHp(int newHp){
this.hp = newHp;
}
public int getHp(){
return this.hp;
}
public void damaged(int damHp){
this.hp -= damHp;
notify();
}
}
private GolemAction golemAction;
public Golem(){
golemAction = new BasicGolemAction();
}
if(summonerHp < 50){
golemAction = new BodyguardGolemAction();
}
public void doAction(){
golemAction.do();
}
}
/* main */
public static void main(String[] args){
Summorner summorner = new Summorner();
summorner.attach(new FireGolem());
summorner.attach(new FireGolem());
while(summorner.getHp() > 0){
summorner.damaged(10);
}
}
이렇게 Observer pattern을 사용하면 상태의 변경에 따른 행동을 달리할 수 있고, 대상과 관찰자를 분리함으로써 결합도를 낮출 수 있다. 위의 예제에서 만약 다른 형태의 골렘을 소환한다 해도 서머너의 입장에서는 구조가 전혀 바뀌지 않는다. 마찬가지로 새로운 골렘을 만들때 관찰 대상에 대한 고려는 update될 때 뿐이다. Observer pattern이 얼마나 강력하지 보여주는 부분이다.
Observer pattern을 조금 더 상세하게 나눈다면, 위의 예제에서와 같이 관찰자에게 관찰 대상의 데이터를 넘겨주는 push communication method와 update(void) 인 메소드 안에서 에서 관찰 대상의 정보를 직접 활용하는 poll communication method 로 나눌 수 있다.
물론 골렘들은 서머너의 상태에만 반응하는 수동적인 생물이 되어버렸지만 서머너의 상태를 매번 확인하면서 행동하는것보단 서머너가 '으악!' 하고 말해줄때 행동하는게 더 효율적인 방법일것이다.
한줄요약 : 관심받고싶다면 관찰자들한테 나를 알려야한다.
'Coding Note' 카테고리의 다른 글
[Design pattern] Factory Method (0) | 2013.01.30 |
---|---|
[Design pattern] Abstract Factory (0) | 2013.01.27 |
[Design pattern] Strategy (0) | 2013.01.19 |
[ExtJs4] nested model (0) | 2013.01.01 |
[MFC] MDI에서 child view 접근 (0) | 2012.10.17 |