Programming/Design Pattern

[디자인 패턴] 옵저버 패턴(Observer Pattern) 찍먹해보기

s.rookie 2022. 4. 7. 18:16

옵저버 패턴이란


옵저버 패턴(Observer Pattern) 이란 객체의 상태 변화를 관찰하는 관찰자, 즉, 옵저버들의 목록을 객체에 등록하여 상태 변화가 있을 때마다 메서드 등을 통해 객체가 직접 목록의 각 옵저버에게 통지하도록 하는 디자인 패턴이다.

 

간단안 예시를 통해서 알아보자.

 

크루들은 코치가 하는 일들에 대해서 알림을 받아야 한다. 코치가 `공지를 한다`면 모든 크루들은 코치가 공지를 했다는 내용에 대해서 알아야 한다.

 

브라운 객체는 코치 인터페이스의 구현체이다. 코치의 기능은 크루들의 등록하고, 등록 해제하고, 크루들에게 알림을 주는 기능을 수행할 수 있다. 루키 객체는 크루 인터페이스의 구현체이다. 크루의 기능은 간단하게 자신의 상태를 업데이트하는 기능을 가진다. 이를 도식화 하면 다음과 같다.

 

 

코드로 간단히 구현한 옵저버 패턴


 

이제 이를 토대로 코드로 구현해보도록 하자.

 

public interface Coach {
    void subscribe(Crew crew);
    void unsubscribe(Crew crew);
    void notifty(Crew crew);
}
public interface Crew {
    void update(String message);
}

 

이렇게 두개의 코치, 크루 인터페이스를 정의할 수 있다. 그럼 위에서 말한 실제 구현체를 한번 작성해보자.

 

public class Brown implements Coach {

    private List<Crew> crews = new ArrayList<>();
    
    public void sayHere() {
    	System.out.println("코치인 브라운이 크루들을 모은다.");
        notify("갈웅파 모여라~");
    }

    public void doDance() {
    	System.out.println("코치인 브라운이 춤을 춘다.");
        notify("춤추실 분 게더로 오세요");
    }
    
    @Override
    public void subscribe(Crew crew) {
        crews.add(crew);
    }
    
    @Override
    public void unsubscribe(Crew crew) {
        crews.add(crew);
    }
    
    @Override
    public void notify(String message) {
        crews.forEach(crew -> crew.update(message));
    }
}

 

브라운은 Crew들의 리스트를 가지고 있고, 각 기능을 가지고 있다. 

 

여기서 중요한 점은 notify 메서드를 각 기능에서 호출한다는 점이다. 그리고 각 크루들에게 한 명씩 업데이트 메서드를 호출하게 된다.

 

 

이제 크루가 코치의 알림을 받고 싶은면 코치에게 구독을 신청하면 된다. 루키는 브라운의 알림을 받고 싶어서 구독을 신청했다. 이를 코드로 나타내면 다음과 같다.

 

public class Main {
    public static void main(String[] args) {
        Coach brown = new Brown();
        
        Crew rookie = new Rookie();
        Crew roma = new Roma();
        Crew huni = new Huni();
        
        brown.subcribe(rookie);        
        brown.subcribe(roma);
        brown.subcribe(huni);
        
        brown.sayHere();
    }
}

 

코치인 브라운에게 루키, 로마, 후니가 구독을 신청하였다. 그리고 sayHere() 메서드를 호출하게 되면 현재 구독중인 3명의 크루들에게 메세지가 전달되게 된다.

 

코치인 브라운이 크루들을 모은다.

Rookie 수신 : 갈웅파 모여라~
Roma 수신 : 갈웅파 모여라~
Huni 수신 : 갈웅파 모여라~

 

만약 구독을 제거하고 싶으면 다음과 같이 구독을 제거할 수 있다.

 

brown.unsubscribe(huni);
brown.sayHere();

 

코치인 브라운이 크루들을 모은다.

Rookie 수신 : 갈웅파 모여라~
Roma 수신 : 갈웅파 모여라~

 

위의 결과처럼 Huni는 알림 대상에게 제거가 된 것을 확인할 수 있다. 

 

위와 같은 플로우를 통해 객체의 상태가 변화될 때 연관된 객체들에게 알림을 보낼 수 있게 된다.