디자인패턴

디자인 패턴 - 옵저버 패턴

개발자 포비 2024. 12. 2. 11:51

객체 간 연관관계와 옵저버 패턴

객체는 서로 연관관계를 이루어 역할을 수행합니다. 예를 들어, A의 변화에 따라 B와 C가 저마다의 역할을 수행하는 것을 기대할 수 있습니다. 이러한 상황에서 개발자가 주의해야 할 점은 다음과 같습니다.

주의해야 할 사항

  1. A는 자신의 변화를 감지하는 객체들을 어떻게 관리할 것인가?
  2. A는 자신의 변화를 B와 C에 어떻게 알릴 것인가?

단순히 B와 C의 객체의 구현체를 A가 직접 들고 있다면 아래와 같은 문제가 발생합니다.

발생 가능한 문제점

  1. 강한 결합: A가 직접적으로 B와 C의 구현체를 들고 있으므로, 강한 결합을 가지게 되어 추후 유지보수가 어렵습니다.
  2. 확장성 부족: D라는 새로운 객체에 대해서도 처리해야 하는 경우, 코드가 비효율적으로 늘어나게 됩니다.
  3. 실수 발생 가능성: A가 변화가 발생했을 때, 변화를 감지하는 몇 객체에 대한 통지를 하지 않는 경우 실수가 발생할 수 있습니다.

옵저버 패턴의 필요성

이러한 문제를 해결하기 위해 옵저버 패턴을 사용합니다. 옵저버 패턴은 Subject라는 변화가 감지되는 대상과 Observer라는 변화를 감지하는 대상으로 구분되어 만들어집니다.

  • 변화를 감지하는 Observer 객체는 Subject 객체의 입장에서 변화 감지 객체를 추상화하여 통지할 수 있는 기능을 제공합니다.
  • 이는 Subject 객체의 확장성을 높이고 객체 간 결합성을 낮추어 OCP 원칙(Open/Closed Principle)에 부합합니다.
  • 변화 감지 대상은 Observer라는 인터페이스를 구현하여 Subject 객체에 등록되어 사용됩니다.
public interface Subject {
    List<Observer> observers = new ArrayList<Observer>();

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

    default void detach(Observer observer){
        observers.remove(observer);
    }

    default void notifyObservers(){
        observers.forEach(Observer::update);
    }
}

public interface Observer {
    void update();
}

public class Content implements Subject {
    public void update(){
        System.out.println("SUBJECT UPDATED");
        notifyObservers();
    }
}

public class ObserverMain {
    public static void main(String[] args) {

        Content subject = new Content();

        // Observer 객체에 Subject 객체를 등록한다.
        // - 변화가 감지되는 경우에 사용하기 위한 목적
        Observer observer1 = new ObserverImpl1(subject);
        Observer observer2 = new ObserverImpl2(subject);

        // 관심을 가지는 객체를 등록한다.
        subject.attach(observer1);
        subject.attach(observer2);

        subject.update();
    }
}