본문 바로가기

JAVA/GOF Design Pattern

GOF Observer Pattern

SMALL

자바 옵저버 패턴(Java Observer Pattern)은 객체지향 프로그래밍에서 많이 사용되는 디자인 패턴 중 하나로, 객체 간의 의존성을 줄이고 유연하게 상호작용할 수 있는 방법을 제공합니다.

옵저버 패턴은 Subject(주체)와 Observer(관찰자)라는 두 개의 인터페이스로 이루어집니다. Subject는 데이터 변경을 관리하고, Observer는 이러한 데이터 변경 사항을 감지하고 이에 따른 행동을 취합니다.

자바에서는 java.util 패키지에서 옵저버 패턴을 구현하는 데 필요한 클래스와 인터페이스를 제공합니다. 예를 들어, Subject를 구현하는 Observable 클래스와 Observer를 구현하는 Observer 인터페이스가 있습니다.

옵저버 패턴의 구현 방법은 다음과 같습니다.

  1. Subject 인터페이스를 구현하는 클래스에서는 Observer 객체들을 등록하고, 데이터가 변경될 때마다 Observer들에게 알립니다.
  2. Observer 인터페이스를 구현하는 클래스에서는 Subject 객체를 등록하고, Subject 객체가 데이터 변경을 알릴 때마다 이를 처리하는 update 메서드를 구현합니다.
  3. 데이터 변경이 발생하면 Subject 객체는 등록된 Observer들에게 알리고, Observer들은 이를 처리하기 위해 update 메서드를 호출합니다.

옵저버 패턴을 사용하면 Subject와 Observer 간의 의존성이 낮아지므로 유연하고 확장성이 높은 코드를 작성할 수 있습니다. 또한, 데이터 변경을 추적하고 처리하는 로직을 Observer에게 위임함으로써 코드의 복잡성을 줄일 수 있습니다.

 

자바에서 옵저버 패턴을 구현하려면 java.util 패키지에서 제공하는 Observable 클래스와 Observer 인터페이스를 사용할 수 있습니다. 아래는 이를 활용한 간단한 예시 코드입니다.

 

Subject(Observable) 클래스:

 

import java.util.Observable;

public class MySubject extends Observable {
    private String data;

    public MySubject(String data) {
        this.data = data;
    }

    public void setData(String data) {
        this.data = data;
        setChanged();
        notifyObservers();
    }

    public String getData() {
        return data;
    }
}

 

Observer 인터페이스를 구현한 ConcreteObserver 클래스:

 

import java.util.Observable;
import java.util.Observer;

public class MyObserver implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        if (o instanceof MySubject) {
            MySubject mySubject = (MySubject) o;
            System.out.println("Data changed: " + mySubject.getData());
        }
    }
}

 

위 코드에서 MySubject 클래스는 Observable 클래스를 상속받고, setData() 메서드에서 데이터를 변경하고 setChanged() 메서드로 데이터 변경을 알립니다. 이후 notifyObservers() 메서드를 호출해 등록된 Observer들에게 데이터 변경을 알립니다.

MyObserver 클래스는 Observer 인터페이스를 구현하고 update() 메서드에서 데이터 변경을 처리합니다.

아래는 이를 활용한 실행 코드입니다.

 

public class Main {
    public static void main(String[] args) {
        MySubject subject = new MySubject("initial data");
        MyObserver observer = new MyObserver();
        subject.addObserver(observer);

        subject.setData("new data");
    }
}

 

위 코드에서 MySubject 객체를 생성하고, registerObserver() 메서드를 통해 MyObserver 객체를 등록합니다. 이후 setData() 메서드를 호출하여 데이터를 변경하면 등록된 Observer에게 데이터 변경을 알리고, MyObserver에서 이를 처리합니다.

 

POJO(Plain Old Java Object)로 옵저버 패턴을 구현하려면, Subject와 Observer를 각각 인터페이스로 추상화하고, 이를 구현하는 클래스를 생성하여 구현합니다. 아래는 POJO로 구현된 간단한 예시 코드입니다.

 

Subject 인터페이스:

 

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

 

Observer 인터페이스:

 

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

 

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

public class MySubject implements Subject {
    private String data;
    private List<Observer> observers;

    public MySubject(String data) {
        this.data = data;
        observers = new ArrayList<>();
    }

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

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

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

    public void setData(String data) {
        this.data = data;
        notifyObservers();
    }
}

 

Observer를 구현한 ConcreteObserver 클래스:

 

public class MyObserver implements Observer {
    private String data;

    @Override
    public void update(String data) {
        this.data = data;
        System.out.println("Data changed: " + data);
    }
}

 

위 코드에서 MySubject 클래스는 Subject 인터페이스를 구현하고, registerObserver() 메서드로 Observer를 등록하고, removeObserver() 메서드로 Observer를 삭제하며, setData() 메서드에서 데이터를 변경하면 notifyObservers() 메서드를 호출하여 등록된 Observer에게 데이터 변경을 알립니다.

MyObserver 클래스는 Observer 인터페이스를 구현하고, update() 메서드에서 데이터 변경을 처리합니다.

아래는 이를 활용한 실행 코드입니다.

 

public class Main {
    public static void main(String[] args) {
        MySubject subject = new MySubject("initial data");
        MyObserver observer = new MyObserver();
        subject.registerObserver(observer);

        subject.setData("new data");
    }
}

 

위 코드에서 MySubject 객체를 생성하고, registerObserver() 메서드를 통해 MyObserver 객체를 등록합니다. 이후 setData() 메서드를 호출하여 데이터를 변경하면 등록된 Observer에게 데이터 변경을 알리고, MyObserver에서 이를 처리합니다.

 

옵저버 패턴은 Subject(주체)와 Observer(관찰자) 간의 일 대 다 관계를 가지는 패턴으로, UML 클래스 다이어그램에서는 다음과 같이 표현됩니다.

Subject 인터페이스는 registerObserver(), removeObserver(), notifyObservers() 메서드를 가지며, ConcreteSubject 클래스에서는 이를 구체적으로 구현합니다.

Observer 인터페이스는 update() 메서드를 가지며, ConcreteObserver 클래스에서는 이를 구체적으로 구현합니다.

ConcreteSubject 클래스는 Subject 인터페이스를 구현하며, 등록된 Observer 객체들에게 notifyObservers() 메서드를 호출하여 데이터의 변경을 알립니다.

ConcreteObserver 클래스는 Observer 인터페이스를 구현하며, update() 메서드에서 데이터 변경을 처리합니다.

위의 클래스 다이어그램에서는 Subject 인터페이스와 Observer 인터페이스를 추상화된 클래스로 표현하지 않았지만, 구체적으로 구현할 때 이를 추상화된 클래스로 구현할 수도 있습니다.

 

LIST

'JAVA > GOF Design Pattern' 카테고리의 다른 글

GOF Builder Pattern  (0) 2023.05.09
GOF 스트레티지 패턴(Strategy Pattern)  (0) 2023.05.09
GOF Abstract Factory Pattern  (0) 2023.05.08
GOF Iterator 패턴  (0) 2023.04.28
Gof Template method 패턴  (0) 2023.04.28