디자인 패턴 - 옵저버 (Observer)

Jae Chan·2023년 8월 9일
2

Pattern

목록 보기
3/3
post-thumbnail

옵저버(Observer) 패턴

Observer 🔭

  • 옵저버 패턴객체간의 의존성을 관리하며 객체의 상태변화를 감지해 다른 객체에게 알려주는 패턴이다.

얼마 전, 안드로이드 앱을 개발하며 브로드캐스트 리시버 컴포넌트에 대해 모르는 부분이 많아 안드로이드 공식 문서와 여러 사이트에서 참고했었다.

그 중 옵저버 패턴이 해당 컴포넌트에 사용됐다고 하기에 옵저버 패턴이 무엇인지 궁금해 오랜만에 디자인 패턴을 공부해보려고 함 😳


🔭 옵저버 패턴의 특징

  • 객체간의 느슨한 결합
    주체와 옵저버 사이의 의존성을 최소화하며 각 컴포넌트를 독립적으로 수정하고 확장할 수 있다.

  • 유연성과 확장성
    새로운 옵저버를 추가하거나 기존 옵저버를 제거하여도 주체 클래스를 수정할 필요가 없다.

  • 구조적 모듈성
    주체와 옵저버들 간의 관계가 구조적으로 정리되어 코드의 가독성 및 모듈성을 향상시킨다.

  • 이벤트 기반 시스템 구축
    상태 변화와 관련된 이벤트를 효율적으로 관리하고 처리할 수 있다.

✅ 장점

  • 새로운 기능을 추가하거나 변경해야할 때 주체와 옵저버를 수정하지 않고도 사용 가능하다.
  • 주체와 옵저버들의 역할과 책임이 분리되어 코드의 구조가 정돈된다.
  • 이벤트 기반 아키텍처에서 상태 변화를 처리하기에 적합하며, 복잡한 로직을 단순화 할 수 있다.

❌ 단점

  • 주체와 옵저버 사이의 강한 참조 관계로 인해 메모리 누수가 발생될 수 있다.
  • 옵저버가 여러 개 등록되어 있는 경우에 알림을 받는 순서가 보장되지 않을 수 있다.
  • 너무 많은 옵저버가 등록될 경우 알림을 전달하는 과정에서 성능 저하가 발생될 수 있다.

사용 예시 : 게시판 알림

하나의 예시를 들어보겠다. 현재 게시판 시스템을 개발중이며 새로운 글이 게시될 경우 게시판 사용자들에게 알림을 보내는 기능을 구현하고 싶다. 이 때 옵저버 패턴을 적용할 수 있다.

👨‍💻 다이어그램

3개의 클래스와 1개의 인터페이스가 존재한다.

  • 옵저버 인터페이스(Obserber)
    상태 변화에 따라 동작할 메소드들을 선언한 인터페이스이다. 구체화 될 옵저버 클래스에서 구체적인 동작을 선언해준다.

  • 주체 클래스(PostSubject)
    상태를 가지고 있는 객체이다. 이 상태가 변경될 때 옵저버에게 상태 변화를 알려주는 클래스이다. 주체 클래스는 주로 옵저버의 관리 및 삭제를 담당옵저버에게 알림을 전달하는 역할을 갖고 있다.

  • 구체화된 옵저버 클래스(UserObserver)
    옵저버의 실제 역할을 정의하는 클래스이다. 주로 주체의 상태 변화에 따라 필요한 작업을 수행하도록 구현된다. 예를 들어 알림을 받아 화면에 출력하는 역할을 한다.

  • 구체화된 주체 클래스(ConcretePostSubject)
    주체 클래스를 확장하여 상태를 갖고 있는 실제 클래스를 구현한 클래스이다. 구체화된 주체 클래스는 주로 주체의 상태를 변경하는 메소드와 함께 알림을 보내는 역할을 한다.

옵저버 (Observer)

사용자에게 알림을 보내기 위한 옵저버 인터페이스를 먼저 구현한다.

// 사용자에게 알림을 보내기 위한 옵저버 인터페이스
public interface Observer {
    void update(String post);
}

주체 클래스 (PostSubject)

주체 클래스는 게시글을 작성하고 게시하는 역할을 한다.

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

public class PostSubject {
    private List<Observer> observers = new ArrayList<>();
    private String post;

    // 게시글 등록
    public void attach(Observer observer) {
        observers.add(observer);
    }

    // 게시글 삭제
    public void detach(Observer observer) {
        observers.remove(observer);
    }

    // 게시글 업데이트
    public void setPost(String post) {
        this.post = post;
    }

    // 알림을 보내는 역할을 하는 옵저버
    private void notifyObserver() {
        for (Observer observer : observers) {
            observer.update(post);
        }
    }
}

구체적인 옵저버 클래스 (UserObserver)

구체적인 옵저버 클래스는 사용자들이 구독하며 새로운 글이 게시되면 알림을 받는 역할을 할 수 있다.

public class UserObserver implements Observer {
    private String userName;

    // 생성자(Constructor)
    public UserObserver(String userName) {
        this.userName = userName;
    }

    @Override
    public void update(String post) {
        System.out.println("알림 : 🔔" + userName + "님, 새로운 글이 올라왔어요! ");
        System.out.println("새로운 글 제목 : " + post);
    }
}

구체적인 주체 클래스 (ConcretePostSubject)

게시글을 작성하고 상태 변화가 발생했을 때 등록된 옵저버를 통해 알림을 전송하는 구체 클래스이다.

public class ConcretePostSubject extends PostSubject {
    @Override
    public void setPost(String post) {
        super.setPost(post);
    }
}

이러한 구현을 통해 기존의 주체 클래스(PostSubject)의 동작을 유지하면서, 필요한 경우에
추가적인 기능을 유지하거나 변경할 수 있게 된다.

여기서 모듈의 유연성 및 확장성의 장점이 드러나게 되는 것이다.

테스트

위에서 구현한 코드를 테스트한 결과이다.

public class Test {
    public static void main(String[] args) {
        // 게시판 주체를 생성한다.
        ConcretePostSubject postSubject = new ConcretePostSubject();
        // 옵저버를 생성한다.
        UserObserver user_0 = new UserObserver("Jae Chan");
        UserObserver user_1 = new UserObserver("User 1");
        /* 두 개의 옵저버를 등록한다.
         * 주체 클래스는 상태변화를 옵저버에게 알린다. */
        postSubject.attach(user_0);
        postSubject.attach(user_1);

        // 게시글 작성 및 옵저버 알림.
        postSubject.setPost("첫 번째 글을 써봐요.");
        // 옵저버 제거
        postSubject.detach(user_1);
        System.out.println("=== 옵저버(user_1)를 삭제한 후의 결과 ===");
        // 또 다른 게시글을 작성하고 이를 옵저버에게 알린다!
        postSubject.setPost("커피가 마시고 싶어요 ㅠㅠ");
    }
}

옵저버를 두 개를 생성한 후 게시글을 작성하면 두 개의 옵저버로부터 글 알림이 올 것이고, 옵저버를 삭제한 후 새로운 글을 작성하면 하나의 알림만 올 것이다.

코드 실행을 해보면 다음과 같이 출력된 것을 알 수 있다.

알림 : Jae Chan님, 새로운 글이 올라왔어요! 
새로운 글 제목 : 첫 번째 글을 써봐요.
알림 : User 1님, 새로운 글이 올라왔어요! 
새로운 글 제목 : 첫 번째 글을 써봐요.

=== 옵저버(user_1)를 삭제한 후의 결과 ===
알림 : Jae Chan님, 새로운 글이 올라왔어요! 
새로운 글 제목 : 커피가 마시고 싶어요 ㅠㅠ

이와 같이 주체 클래스에서 상태변화를 옵저버에게 알려주고, 등록된 옵저버들은 알림을 받아 텍스트를 출력한 것을 알 수 있다.


마치며

종강 후에 취업까지 하게되며 개발 공부와 담을 쌓고 롤토체스 삼매경인 요즘, 리프레시를 위해 디자인 패턴을 공부해봤다. 디자인 패턴은 늘 처음 볼 땐 생소한 부분이 많은데 이해하면 유용한 지식임에 분명한 것은 틀림없다. 😗

💬 참고 자료

0개의 댓글