728x90

참고:

http://blog.naver.com/PostList.nhn?blogId=paoscom

아래의 아이콘들은 위의 블로그에서 가져왔음을 밝힙니다.


옵저버 패턴은 자주 쓰이는 패턴중 하나이다.

어떤 상황에서 쓰이는지 예를 들어보자.


현재 시간은 9시이다.

각각의 직업마다 내가 해야할게 다르다.

이걸 일종의 상태라고 생각해보자.


일단 시계를 클래스로 만들어보자.


package example;

public class Clock {
public String time;

public Clock(String time) {
this.time = time;
}
}

정말 간단하게 만들었는데 뭐 이해... 못하는 사람은 없을것 같다.


package example;

public class Doctor {
public Clock clock;
public String state = "보통";

public Doctor(Clock clock) {
this.clock = clock;
}
}
package example;

public class Developer {
public Clock clock;
public String state = "보통";

public Developer(Clock clock) {
this.clock = clock;
}
}
package example;

public class Nerd {
public Clock clock;
public String state = "보통";

public Nerd(Clock clock) {
this.clock = clock;
}
}

그 다음 사람들 코드를 만들어 놓았다.


package example;

public class Main {
public static void main(String[] args) {
Clock c = new Clock("8");
Doctor doctor = new Doctor(c);
Developer developer = new Developer(c);
Nerd nerd = new Nerd(c);
}
}

이렇게 시계는 단 한개를 만들고 3명이서 쓰게 만드는 코드는 아주 흔하다.

흔하다라는 말로는 모자라다. 시간은 모두 똑같으니까 모두 코드를 짠다면 이렇게 비슷하게 짤 것이다.


자 이제 기본적으로 만들어 놨으니까 다시 문제에 접근해보자.



9시 전까지는 모두 "보통"상태에서 의사는 "야근", 개발자는 "퇴근", 백수는 "드라마"라는 코드를 만들고 싶다.


... 어떻게?


물론 만드는 방법이야 아주 다양하지만 만약 여러분이 원하는게


시간이 바뀌면 나머지 사람들의 상태가 자동으로 바뀌게하기


위와 같다면 어떻게 구현할 것인가? 생각보다 쉽지 않다는걸 알게 될 것이다.



왜냐하면 사람들이 시간이 바뀌는걸 감지할 방법


을 구현하는게 쉽지 않기 때문이다.


이를 위하여 만든 디자인 패턴이 바로 Observer 패턴이다.



출처 - https://ko.wikipedia.org/wiki/%EC%98%B5%EC%84%9C%EB%B2%84_%ED%8C%A8%ED%84%B4

클래스 다이어그램은 위와 같은데 가장 중요한 개념은 Subject(Publisher)와 Observer이다.


Subject(Publisher) - 변화하는 녀석을 Subject라고 부른다. 즉 우리는 이 녀석의 변화를 감지하고 싶다.

Observer - 변화를 감시하는 녀석을 변화가 필요한 녀석에 달아놓는다... 말이 좀 이상하게 됬는데 쉽게 말하면 Subject의 변화를 감시를 하겠다는 것이다.


뭔가 말로하면 어려운 개념같다.

사실 어렵진 않은데 좀더 쉽게 표현해보겠다.




즉 Subject가 변화하는 순간 각각에 심어놓은 Observer에게 알리고 옵저버는 그걸 바탕으로 객체를 변화시킨다.


그럼 기존의 코드에서 변화시켜보자.


package example;

public interface Observer {
void update();//notify
}

옵저버는 위처럼 interface로 구현한다.

보통 이름을 update라고 하는데 notify라고 안하는 이유는 자바의 Object에 이미 notify가 있기 때문이다.


package example;

public interface Subject {
void registerObserver(Observer observer);
void unregisterObserver(Observer observer);
void notifyObservers();
}

Subject에서는 Observer를 핸들링할 메소드들을 만든다.

변수도 만들고 싶지만 자바에서는 interface에서 일반 변수를 선언할 수 없다.

그래서 어쩔수 없게 위처럼 작성한다.


이제 기존의 코드들을 바꿔보자


package example;

import java.util.ArrayList;

public class Clock implements Subject{
public ArrayList<Observer> observerCollection;
public String time;

public Clock(String time) {
observerCollection = new ArrayList<>();
this.time = time;
}

@Override
public void registerObserver(Observer observer) {
observerCollection.add(observer);
}

@Override
public void unregisterObserver(Observer observer) {
observerCollection.remove(observer);
}

@Override
public void notifyObservers() {
for(Observer observer:observerCollection){
observer.update();
}
}

public void setTime(String time) {
this.time = time;
notifyObservers();
}
}

subject를 상속받아서 clock을 구현한다.


public Clock(String time) {
observerCollection = new ArrayList<>();
this.time = time;
}

생성자에서는 observer를 모아둘 녀석을 만든다.


public void setTime(String time) {
this.time = time;
notifyObservers();
}

그리고 여러분이 바꿔야할 값을 직접 바꾸지말고 setter를만든다(물론 실전에서는 다 get,set을 쓸거니까 상관없긴하다.)

이 때 바뀌는 값에 반드시 notifyObservers를 사용한다.

그래야 옵저버들에게 변한것을 알릴 수 있기 때문이다.


package example;

public class Doctor implements Observer {
public Clock clock;
public String state = "보통";

public Doctor(Clock clock) {
this.clock = clock;
this.clock.registerObserver(this);
}

@Override
public void update() {
//action!
{
if (clock.time.equals("9")) {
state = "야근";
}
}
}
}

그 다음 모든 코드에서 추가해줄 것은 update내용을 구현해주는것, 그리고 반드시 subject에 이 옵저버를 등록시켜야한다.


public Doctor(Clock clock) {
this.clock = clock;
this.clock.registerObserver(this);
}

Doctor자체가 Observer이므로 등록시켜준다.

여기서 Clock자체가 이미 Subject이므로 여기에다가 자기자신을 등록시켜주면된다.


package example;

public class Main {
public static void main(String[] args) {
Clock c = new Clock("8");
Doctor doctor = new Doctor(c);
Developer developer = new Developer(c);
Nerd nerd = new Nerd(c);

//변화전
{
System.out.println(doctor.state);
System.out.println(developer.state);
System.out.println(nerd.state);
}

//시간 변화
{
c.setTime("9");
}

//변화후
{
System.out.println(doctor.state);
System.out.println(developer.state);
System.out.println(nerd.state);
}
}
}

main을 보면 추가된 코드말고는 바뀐게 없다.

커플링이 느슨해진걸 확인할 수 있다.

그럼 출력해서 진짜 바뀌는지 보도록 하자.



값이 성공적으로 변화한걸 확인할 수 있다.

'Design Pattern' 카테고리의 다른 글

[DesignPattern]오직 하나뿐인 객체, 싱글톤 패턴  (0) 2018.11.04

+ Recent posts