도찐개찐

[코드디자인패턴-JAVA] Observer Pattern 본문

프로그래밍/코드디자인패턴

[코드디자인패턴-JAVA] Observer Pattern

도개진 2024. 2. 29. 09:31

Observer Pattern

사용시점

  1. 상태 의존성: 하나의 객체의 상태 변경이 다른 객체의 상태나 동작에 영향을 미칠 때
  2. 이벤트 발생: 특정 이벤트가 발생했을 때 관찰자들에게 알림을 보낼 필요가 있을 때
  3. 코드 결합 최소화: 주제와 관찰자 사이의 결합을 최소화 하고자 할때

종류

  1. 푸시 모델: 주제가 관찰자에게 필요한 모든 정보를 직접 보내는 방식, 관찰자는 주제로부터 푸시된 정보만을 이용합니다.
  2. 풀 모델: 주제가 변화를 통보만 하고, 관찰자는 필요한 정보를 주제로부터 직접 가져오는 방식입니다. 이 경우 관찰자가 필요한 정보만을 가져올 수 있으며, 주제와 관찰자 사이의 의존성이 낮아 집니다.

결론

  1. 상태 변화를 관찰하는 객체들에게 상태 변화를 알려주는 패턴
  2. 주로 이벤트 핸들링 시스템에서 사용되며, 하나의 주제(Subject) 객체와 그 주제를 관찰하는 관찰자(Observer) 객체들로 구성.

Push Model(푸시모델)

1. Observer 인터페이스: 관찰자 정의

public interface Observer {
    void update(String message);
}

2. Subject 클래스: 주제를 정의 하고, 관찰자를 등록하거나 제거 합니다.

import java.util.ArrayList;
import java.util.List;

public class Subject {
    private List<Observer> observers = new ArrayList<>();

    public void addObserver(Observer observer) {
        observers.add(observer);
    }

    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    public void notifyObservers(String message) {
        for (Observer observer : observers) {
            observer.update(message);
        }
    }
}

3. ConcreteObser클래스: 실제 관찰자 구현

public class ConcreteObserver implements Observer {
    private String name;

    public ConcreteObserver(String name) {
        this.name = name;
    }

    @Override
    public void update(String message) {
        System.out.println(name + " received message: " + message);
    }
}
public class Main {
    public static void main(String[] args) {
        Subject subject = new Subject();

        Observer observer1 = new ConcreteObserver("Observer1");
        Observer observer2 = new ConcreteObserver("Observer2");

        subject.addObserver(observer1);
        subject.addObserver(observer2);

        subject.notifyObservers("Hello, Observers!");
    }
}

Main.main(null);
Observer1 received message: Hello, Observers!
Observer2 received message: Hello, Observers!
장점
  • 확장성: 새로운 관찰자를 추가하거나 제거하기 쉽습니다.
  • 낮은 결합도: 주제와 관찰자 사이의 결합도가 낮아, 하나를 변경해도 다른 하나에 영향을 미치지 않습니다.
단점
  • 메모리와 성능 문제: 많은 수의 관찰자가 있는 경우, 모든 관찰자에게 알림을 보내는데 비용이 발생 할 수 있습니다.
  • 데이터의 일관성: 관찰자들이 동일한 데이터를 기반으로 작업한다고 보장할 수 없으므로, 데이터 일관성을 유지하는 것이 복잡 할 수 있습니다.

Pull Model(풀모델)

1. Subject 클래스: 관찰의 대상이 되는 클래스로, 상태가 변경 되면 등록 된 Observer들에게 알림

import java.util.ArrayList;
import java.util.List;

public class Subject {
    private List<Observer> observers = new ArrayList<>();
    private int state;

    public int getState() {
        return state;
    }

    public void setState(int state) {
        this.state = state;
        notifyAllObservers();
    }

    public void attach(Observer observer) {
        observers.add(observer);
    }

    public void notifyAllObservers() {
        for (Observer observer : observers) {
            observer.update();
        }
    }
}

2. Observer 추상 클래스: 관찰자들이 구현해야 할 추상 클래스로, Subject의 상태 변경을 알리는 메소드가 정의

public abstract class Observer {
    protected Subject subject;
    public abstract void update();
}

3. ConcreteObserver 클래스: Observer 추상 클래스를 구현한 구체 클래스로, 상태 변경을 알리면 해당 정보를 출력

public class ConcreteObserver extends Observer {
    public ConcreteObserver(Subject subject) {
        this.subject = subject;
        this.subject.attach(this);
    }

    @Override
    public void update() {
        System.out.println("State has been updated to " + subject.getState());
    }
}
public class Main {
    public static void main(String[] args) {
        Subject subject = new Subject();
        new ConcreteObserver(subject);
        subject.setState(10);
    }
}

Main.main(null);
State has been updated to 10

장점

  1. 데이터의 효율성: 관찰자가 필요한 데이터만 주제로부터 가져오므로 불필요한 데이터 전송이 없음
  2. 유연성: 관찰자가 자신이 필요한 데이터를 직접 선택해 가져올 수 있으므로 패턴 유연성 증가

단점

  1. 성능 이슈: 관찰자가 주제로부터 데이터를 가져오는 과정에서 추가 메서드 호출이 필요하므로 성능에 영향 미칠 가능성 있습니다.
  2. 복잡성 증가: 풀 모델에서는 주제와 관찰자 간의 상호작용이 더 복잡해지므로 설계와 유지보수가 어려울 수 있습니다.

대표 사례

  1. Swing: 자바의 GUI 라이브러리인 Swing에서는 사용자 인터페이스의 이벤트 처리에 Observer 패턴을 사용합니다. 이벤트 리스너가 특정 이벤트에 응답하여 액션을 수행하게 됩니다.
  2. JavaBeans: JavaBeans에서는 속성 변경 리스너를 통해 Observer 패턴을 구현합니다. 프로퍼티의 변경을 감지하고 이를 관찰하는 객체에게 알림을 보냅니다.
  3. RxJava: RxJava는 자바에서 리액티브 프로그래밍을 지원하는 라이브러리로, Observer 패턴의 확장된 형태를 제공합니다. Observable이 이벤트를 생성하고 Observer가 이를 구독하며 반응합니다.
  4. Spring Framework: Spring에서는 이벤트 처리 메커니즘에 Observer 패턴을 사용합니다. 이벤트 발생 시 등록된 리스너가 알림을 받고 처리하게 됩니다.
  5. Apache ZooKeeper: 분산 코디네이션 서비스를 제공하는 ZooKeeper도 Observer 패턴을 사용합니다. 클라이언트는 ZooKeeper의 노드에 watch를 걸고 변화를 감지하면 알림을 받습니다.
728x90
Comments