옵저버 패턴

반응형
반응형

Observer 관측자라는 뜻으로 옵저버 패턴, 종속자 패턴, 게시-구독 패턴이라고 한다.

사실 이 패턴을 처음 접했을때는 단순히 난해하다고만 생각했다. 왜냐하면 옵저버 패턴의 가장 큰 특징중 하나가 객체의 느슨한 결합인데... 이것에 의미를 정확하게 인지하지 못하고 있었다. 정확하지는 않지만... 아마 직접 구현이아닌 인터페이스로 만들어서 결합도를 낮추는 방법인듯 싶다. 아무래도 인터페이스로 인스턴스를 만들게 되면 선택지가 많아지기 때문에 아마 맞는것 같다. 

 

해드 퍼스트 디자인 패턴 책에서는 이 패턴을 설명할때, 신문과 구독이라는 주제로 설명했다. 

 

신문사는 여러 종류가 있다.

A 신문사, B신문사, C신문사... 등등 하지만 여기에서는 A신문사만 존재한다고 가정하자.

보통 신문사에는 구독자가 있다. 즉, 고객이다. 여기서 주목해야할 점은 바로 고객이다. 고객은 한 명일 수 도 있지만, 대게는 여러명일것이다. 또한, 고객은 신문사를 구독 해지 할수 있다. 즉, 탈퇴 할 수 있다는 뜻이다. 그래서 고객들은 신문사를 구독할 수 있지만, 동시에 해지도 할 수 있다. 

 

이 상태에서 구현한다고 생각하자.

일단은 인터페이스가 아닌 클래스로 구현해보자.

 

public class Newspaper {
    
    
    public void register() {
        구현
    }
    
    public void remove() {
        구현
    }
    
}

대충 이런 클래스를 만들거다. 고객과 신문사의 관계는 N : 1의 관계다. (신문사 부터 말하면 1:N)

그러면 그들은 List로 만드는게 편할것 같다. 

public class Newspaper {
    private List<Customer> customers = new ArrayList<>();

    public void register(Customer customer) {
        customers.add(customer);
    }

    public void remove(Customer customer) {
        customers.remove(customer);
    }

}

근데... 여기서 문제가 발생한다. 고객은 추가되고, 삭제가 되는데, 현재 이 코드로 만 봤을때는 추가랑 삭제를 하는 주체는 바로 신문사다. 하지만 구독과 해지는 고객이 한다. 그렇기 때문에 고객에서 추가및 삭제에 관련된 메서드가 필요할듯 싶다.

public class Customer {
    
    private Newspaper newspaper;

    public Customer(Newspaper newspaper) {
        newspaper.register(this);
    }

    public void update() {
        System.out.println("구독합니다.");
    }
}

이 로직이 어떤 뜻을 내포하고 있냐면

고객이 신문사에 등록을 요청할때 이 클래스를 등록한다는 뜻으로 해석된다. 이렇게 되면 구독하는 것을 고객이 하는 걸로 탈바꿈 할 수 있다. 

 

뭐 ... 대충 해지 기능도 이런식으로 만들 면 되걸 같다. 물론... 필요 없을 수는 있겠지만....

public void remove() {
   newspaper.remove(this);
}

근데 중요한건 이렇게 다했는데 고객이 어떤 상황인지 신문사는 전혀 모르고 있다. 물론 list에서 빠지기 때문에 리스트 자체는 알고는 있지만, 신문사도 고객이 빠지는 걸 알필요성이 있다.

public void print() {
    for (int i = 0; i < customers.size(); i++) {
       Customer customer = customers.get(i);
        customer.update();
    }
}

자 이렇게 구성하면 이제 print를 호출할때마다 고객이 얼마나 빠졌는지 아닌지 알수 있다. 하지만

 

이렇게 만들면 확장하는데 어려움이 있다. 예를들어, 현재는 신문사A밖에 없다고 가정했지만 점차 신문사라는 사업모델이 인기가 늘면서 신문사B,신문사C도 우후죽순으로 생겨날 것이다. 이때마다 객체를 또 만드는건 굉장히 비효율적이다. 물론, 클래스 자체는 만들어야하겠지만 그래도 이들을 하나로 통합할 수 있는 무언가가 있다면 관리하는데 용이할 것 같다.

public interface New {
    public void register(Customer customer);

    public void remove(Customer customer);
}

또, Customer도 여러개일수도 있으니 하나로 통합시켜줄 무언가가 필요할 것같다.

public interface Customers {
    public void update();
}

이제 클래스가 아닌 인터페이스로 파라미터도 변경할 수 있다.

물론 반대도 마찬가지다. 이렇게 하는 이유는 여러가지 겠지만, 여기에서는 인터페이스의 가장 큰 특징중 하나는 이것을 구현하는 클래스들을 대표해서 사용할 수 있다는 점이다. 이를 느슨한 결합이라고 말한다. 왜 느슨하다고 말하는 이유는

예를들어 Newspare이라는 클래스를 지웠다고 해도 아무런 문제 없이 동작되기 때문이다. 

 

마지막으로 그럼 옵저버 패턴은 언제 사용하는가? 하면 객체가 서로 상호 작용하는 상황일때 발생한다고 한다. 위 처럼 신문사와 고객같은 식으로 말이다. 사실 interface를 Subject랑 Observer로 주는게 맞지만... 그냥 그렇게 주고 싶지 않았다.

 

 

반응형

'디자인패턴' 카테고리의 다른 글

데코레이터 패턴  (0) 2020.05.02
컴포지트 패턴  (0) 2020.05.01
퍼사드 패턴  (0) 2020.04.23
브릿지 패턴  (0) 2020.04.22
어댑터 패턴  (0) 2020.04.21

댓글

Designed by JB FACTORY