묠니르묘묘
꾸준히 성장하는 개발자스토리
묠니르묘묘
전체 방문자
오늘
어제
  • 분류 전체보기 (188)
    • 프로그래밍 (48)
      • 디자인패턴 (4)
      • 예외,에러 (4)
      • Java (29)
      • Kotlin (3)
      • React.js (4)
      • JavaScript (2)
      • Apache Kafka (2)
    • Spring (49)
      • Spring (21)
      • Spring Cloud (3)
      • JPA (25)
    • 코딩테스트 (31)
      • 알고리즘 (5)
      • Java - 백준 (26)
      • Java - 프로그래머스 (0)
    • AWS (7)
    • 데이터베이스 (6)
    • 개발 etc (23)
    • 도서 (5)
    • 회고록 (4)
    • 데브코스-데이터엔지니어링 (15)

인기 글

최근 글

hELLO · Designed By 정상우.
묠니르묘묘

꾸준히 성장하는 개발자스토리

Observer(옵저버) 패턴이란?
프로그래밍/디자인패턴

Observer(옵저버) 패턴이란?

2023. 3. 30. 15:08

🚀 옵저버 패턴이란?

옵저버 패턴

  • 주제(subject)가 변경될 때마다 옵저버(observer)들에게 변화를 알려주는 디자인 패턴
  • 한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체에게 연락이 가고 자동으로 내용이 갱신되는 방식으로 일대다(one-to-many) 의존성을 정의함
주제와 객체를 따로 두는 경우도 있음. 즉, 주제가 객체를 관찰하다가 변화가 생기면 옵저버들에게 알려주는 것

주제는 옵저버들이 인터페이스를 구현한다는 것을 제외하면 옵저버에 대해 아무것도 모른다. 따라서 이들 사이의 결합은 느슨한 결합(Loose Coupling)이다.

  • 옵저버는 언제든지 새로 추가 및 제거 가능
  • 새로운 형식의 옵저버를 추가할 때도 주제는 변경할 필요 X
  • 주제와 옵저버는 서로 독립적으로 재사용 O
  • 주제나 옵저버가 달라져도 서로에게 영향 X

 

 🚀 예시 코드 작성해보기

Producer(프로듀서)의 데이터가 변경될 때마다 Consumer(컨슈머)들에게 변화를 알려주는 예시를 작성해보자.

예시 코드 구조

  • 주제는 여러개의 옵저버가 있을 수 있음
  • 주제는 상태가 바뀔때마다 notifyObservers()로 옵저버들에게 알려줘야 함
  • 옵저버가 되려면 Observer 인터페이스만 구현하면 됨

Subject 인터페이스

옵저버 등록, 제거, 변화를 알려주는 메서드가 있음

public interface Subject {
    void registerObserver(Observer o);
    void removeObserver(Observer o);
    void notifyObservers();
}

 

Producer 클래스

  • Subject 인터페이스를 구현한 클래스
  • 상태값으로 dataA, dataB를 가짐
  • 전체 상태값을 변경하는 setData() 사용 시, notifyObservers()로 옵저버들에게 변화를 알려줌
  • 상태값 각각의 getter 메서드도 구현되어 있음. 이는 옵저버들이 풀 방식으로 상태값을 직접 가져오기 위함
옵저버 패턴을 사용하면 주제가 데이터를 보내는 푸쉬(push) 방식과 옵저버들 각각 원하는 데이터만 직접 가져오는 풀(pull) 방식이 있다. 일반적으로 풀 방식이 더 옳은 방식으로 간주하고 있다.
public class Producer implements Subject {
    private final List<Observer> observers;
    private String dataA;
    private String dataB;

    public Producer() {
        observers = new ArrayList<>();
    }

    @Override
    public void registerObserver(Observer o) {
        observers.add(o);
    }

    @Override
    public void removeObserver(Observer o) {
        observers.remove(o);
    }

    @Override
    public void notifyObservers() {
        observers.forEach(Observer::update);
    }

    public void setData(String dataA, String dataB) {
        this.dataA = dataA;
        this.dataB = dataB;
        notifyObservers();
    }

    public String getDataA() {
        return dataA;
    }

    public String getDataB() {
        return dataB;
    }
}

 

Observer 인터페이스

public interface Observer {
    void update();
}

 

ConsumerA 클래스

  • Observer 인터페이스를 구현한 클래스
  • 주제를 저장하지 않아도 되지만, 추후 옵저버 목록에서 탈퇴할 때 유용함
public class ConsumerA implements Observer {
    private String dataA;
    private Producer producer;

    public ConsumerA(Producer producer) {
        this.producer = producer;
        producer.registerObserver(this);
    }

    @Override
    public void update() {
        dataA = producer.getDataA();
        System.out.println("ConsumerA가 수정됨 : " + dataA);
    }
}

 

ConsumerB 클래스

  • ConsumerA와는 다르게 dataB만을 필요로하는 클래스
  • 따라서 주제가 변경되면 주제에서 원하는 데이터만 직접 가져오는 풀 방식이 더 좋음
public class ConsumerB implements Observer {
    private String dataB;
    private Producer producer;

    public ConsumerB(Producer producer) {
        this.producer = producer;
        producer.registerObserver(this);
    }

    @Override
    public void update() {
        dataB = producer.getDataB();
        System.out.println("ConsumerB가 수정됨 : " + dataB);
    }
}

 

테스트해보기

class ObserverTest {
    @Test
    void start() {
        Producer producer = new Producer();
        ConsumerA consumerA = new ConsumerA(producer);
        ConsumerB consumerB = new ConsumerB(producer);

        producer.setData("AAA", "BBB");

        producer.removeObserver(consumerA); // consumerA 옵저버 제거

        producer.setData("CCC", "DDD");
    }
}
/*
ConsumerA가 수정됨 : AAA
ConsumerB가 수정됨 : BBB
ConsumerB가 수정됨 : DDD
*/

위 코드는 여기를 클릭하면 나옴

 

🚀 결론

  • 주제와 옵저버 모두 인터페이스를 사용해서 느슨한 결합을 만듦
  • 옵저버 패턴에서는 구성을 활용해서 옵저버들을 관리하므로 확장성 좋음
  • 옵저버들은 서로 독립적이기 때문에 하나의 옵저버가 문제 발생하더라도 다른 옵저버는 영향이 없음
  • 옵저버 객체가 많아질수록 모든 옵저버 객체에 대한 처리를 해야하므로 성능 저하될 가능성 있음
저작자표시 비영리 (새창열림)

'프로그래밍 > 디자인패턴' 카테고리의 다른 글

Decorator(데코레이터) 패턴이란?  (0) 2023.04.18
Strategy Pattern(전략 패턴)이란?  (0) 2023.03.21
Delegate Pattern(델리게이트 패턴, 위임 패턴)이란?  (1) 2023.03.15
    '프로그래밍/디자인패턴' 카테고리의 다른 글
    • Decorator(데코레이터) 패턴이란?
    • Strategy Pattern(전략 패턴)이란?
    • Delegate Pattern(델리게이트 패턴, 위임 패턴)이란?
    묠니르묘묘
    묠니르묘묘

    티스토리툴바