Design Pattern, Observer

2022. 1. 21. 11:00ETC/Design Patterns

반응형

Object Behavioral Pattern

Observer Pattern

 

-----------------    INDEX     -----------------

 

Observer Pattern ?

hollywood principle

Structure

Sample Code: Java

관련 패턴

 

----------------------------------------------

 

 

Define a one-to-many dependency between objects so that when one object changes state,
all its dependents are notified and updated automatically.


- GoF Design Patterns

 

옵저버 패턴은 개체 간의 일대다 종속성을 정의하여,

한 개체의 상태가 변경될 때 모든 종속 개체가 자동으로 알림을 받고 업데이트되는 패턴입니다.

 

 

옵저버 패턴은 할리우드 원칙을 적용한 패턴입니다.

이 패턴은 할리우드 원칙을 이해하면 바로 존재 이유를 아시게 될 것입니다.

 

 

 

Hollywood Principle

객체지향의 설계 원칙 중 할리우드 원칙이 있습니다.

영화 산업으로 유명한 할리우드에서 배우를 캐스팅하는 과정 객체에 비유한 데서 만들어진 원칙인데요.

 

아래와 같은 상황이 있을 수 있습니다.

 

배우가 영화에 출연하기 위해 자신의 프로필을 영화사에 전달합니다.
그리곤 캐스팅 여부를 지속적으로 물어보겠죠.
영화사 입장에서는 매일 연락하는 배우들에게 캐스팅 상태를 통보해주기 어렵습니다.

그래서 영화사는 모든 배우에게 “앞으로 연락하지 말고 캐스팅되면 저희가 연락 드리겠습니다”라고 공지하고, 배우는 캐스팅 상태를 영화사에 물어보지 않은 채 통보를 기다리는 것입니다.

 

 

배우(감시자, observer)가 캐스팅 여부를 지속적으로 물어보는 것이 아니라,

영화사(주체, subject)가 캐스팅 상태(Event)가 변경될 때 배우들에게 전달할는 것입니다.

 

다른 예시를 들어보면, 면접을 치르는 취준생이 있다고 할 때

취준생은 면접 결과를 계속해서 물어보는 게 아니라 지원한 회사에서 결과가 나오면 그 때 통보를 해주게 되죠.

 

 

감시자 패턴은 할리우드 원칙을 적용한 패턴 구현입니다.

수시로 상태에 대한 변화를 물어보면 그 요청에 대한 비용이 발생하고, 그 수가 여러개라면 비용은 급증할 것입니다.

어떤 UI 프레임워크에서는 옵저버 패턴을 리스너 패턴Listener Pattern 이라고도 부릅니다.

이름이 바로 납득 가죠?

 

그래서 상태 변화라는 이벤트가 발생할 때 그 내용을 전달하는 형식이 바로 옵저버 패턴입니다.

 

 

 

1 : N Relationship

하나의 실제 주체ConcreteSubject는 다수의 객체를 가지며 일대다 관계를 가지는 복합 구조 객체가 됩니다.

실제 코드를 확인해 보면, 실제 주체는 옵저버들을 담는 리스트를 가집니다.

 

public class ConcreteSubject implements Subject {
    private ArrayList<Observer> objs;
    
    // 필수 메서드 
}

 

상태 변화가 발생하면 주체는 등록된 모든 감시자 객체에게 반복문 등을 이용하여 변경을 통보하며, 이를 푸시형 통보라고 합니다

주체와 객체간에는 상호 작용이 발생하며, 모든 감시자는 주체에 의해 갱신되기를 기다리고 있습니다.

 

 

 

Interface

Subject는 옵저버들을 관리하기 때문에 가져야 하는 메소드가 있습니다.

 

public interface Subject {
	void attach(Observer obs);
	void detach(Observer obs);
	void notify();
}

 

이름을 보면 알 수 있듯이, Observer 객체를 추가하고, 삭제하고, 알림을 주는 기능들을 작성해야합니다.

notify에서는 Observer를 순회하며 다음으로 소개할 순회 객체의 update()메서드를 부릅니다. 

 

Observer에서는 인터페이스에 update() 메소드가 있습니다.

 

public interface Observer {
    void update();
}

 

이벤트를 듣는 구독 객체가 notify를 받고 상태를 업데이트하는 로직입니다.

더 자세한 설명은 아래 Structure 섹션에서 확인해볼게요!

 

 

 

VS Pub-Sub Pattern

 

옵저버 패턴은 게시-구독publish-subscribe 의 형태입니다. 

일대다 구조의 감시자 패턴에서는 주체가 변화 상태를 모든 객체에 일방적인 단방향성으로 통보합니다.

단방향성을 가진 옵저버 패턴은 게시-구독publish-subscribe 패턴과 비슷합니다.

 

하지만, 사실 엄밀히 말하면 두 패턴은 차이가 있습니다.

 

Image Source: developers-club

 

 

이 둘은 이벤트를 발행하고 구독한다는 역할은 동일하지만,

publish/subscribe 모델은 흔히 Message Broker 또는 Event Bus 등의 Broker가 존재합니다.

 

 

 

Broker로 인한 Pub-Sub Pattern이 갖는 특징은 아래와 같습니다.

 

✔️ publisher - subscriber 간의 관계

Observer Pattern에서는 publisher와 subscriber가 밀접한 관계를 갖지만,

Pub-Sub Pattern에서는 publisher와 subscriber가 서로의 존재를 모릅니다.

 

✔️ 낮은 결합도

 

✔️ N:M 관계

Observer Pattern은 1:N관계라고 했는데요, 

Pub-Sub Pattern에서 중개자가 있기 때문에 N:M 관계인 다대다 관계를 구현할 수 있습니다.

 

 

 

Broker로 MessageQueue를 많이 사용하는데요.

그래서 Pub-Sub Pattern은 대부분 비동기asynchronous 방식으로 동작한다고 합니다.

 

 

 

 

Structure

 

[GoF Design Patterns] - Observer Class Diagram

 

 

Subject

관찰자Observer를 알고(담고) 있으며, Observer는 개수에 상관없이 Subject를 관찰할 수 있습니다.
Observer 개체를 부착attach() 및 분리detach()할 수 있는 인터페이스를 제공합니다.

 

 

Observer

 update() 인터페이스를 정의하여 Subject의 변경 사항에 대해 알림을 받을 수 있도록 합니다.

 

 

ConcreteSubject

ConcreteObserver 객체가 구독할 상태state를 저장합니다.

상태가 변경되면 Observer에게 알림을 보냅니다.

 

 

ConcreteObserver

ConcreteSubject 객체에 대한 참조를 유지합니다.

Observer의 update() 인터페이스를 구현하며,

Subject 일관성을 유지해야 하는 상태를 저장할 수 있습니다.

 

 

 

 

Sample Code: Java

 

Subject

public interface Subject {
    void attach(Observer obs);
    void detach(Observer obs);
    void noti();
}

 

Observer

public interface Observer {
    void update();
}

 

ConcreteSubject

public class Members implements Subject {
    private ArrayList<Observer> objs;

    public Members() {
        objs = new ArrayList<>();
    }

    @Override
    public void attach(Observer observer) {
        objs.add(observer);
    }

    @Override
    public void detach(Observer observer) {
        int index = objs.indexOf(observer);
        objs.remove(index);
    }

    @Override
    public void noti() {
        for(Observer obj : objs) {
            obj.update();
        }
    }
}

 

ConcreteObserver - UserA, UserB

public class UserA implements Observer {
    private String name;

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

    @Override
    public void update() {
        System.out.println(name + " 갱신됩니다.");
    }
}

 

UserB는 UserA와 동일합니다.

 

 

Client

public class Client {
    public static void main(String[] args) {
        Members subject = new Members();

        UserA userA = new UserA("Jiny");
        UserB userB = new UserB("Reilly");

        subject.attach(userA);
        subject.attach(userB);

        subject.noti();
    }
}

 

 

출력

Jiny 갱신됩니다.
Reilly 갱신됩니다.

 

 

 

 

관련 패턴

C- Creational Patterns  |  S - Structural Patterns  |  B - Behavioral Patterns

 

 

B: Mediator

중재자 패턴은 두 개체가 직접 통신하는 것이 아니라 중심 객체가 통신을 중재합니다.

객체에 발생한 상태를 다른 객체에 전달하며,

상태 변화를 통보하는 측면에서 봤을 때 유사하지만 둘의 목적이 다릅니다.

 

감시자 패턴은 상태만 통보하고 중재자 패턴은 역할 조정을 목적으로 통보합니다.

 

 

참고: MVC

MVC 모델에서 Observer 패턴이 사용됩니다.

Model주체Subject에 해당하고 View감시자Observer 역할을 수행하는 구조로 설계됩니다.

 

 

 

 

 

 

 

그럼 지금까지 Observer Pattern에 대해 알아보았습니다.

오타나 잘못된 내용이 있다면 댓글로 남겨주세요!

감사합니다 ☺️ 

 

 

 

모든 Design Patterns 모아보기

 

Design Patterns

안녕하세요. GoF 디자인 패턴을 정리하고자 합니다. 디자인 패턴은 일주일 전부터 공부를 시작했는데, 스스로 설명하듯 적는게 익히는데 도움이 클 것같아 정말 오랜만에 시리즈로 포스팅하려

gngsn.tistory.com

 

 

반응형

'ETC > Design Patterns' 카테고리의 다른 글

Design Pattern, Mediator  (0) 2022.01.24
Design Pattern, Adapter  (0) 2022.01.23
Design Pattern, Proxy  (0) 2022.01.12
Design Pattern, Abstract Factory  (0) 2022.01.05
Design Pattern, Factory Method  (0) 2022.01.03