seops

[Concepts] Observer Pattern 본문

Android/Design Pattern

[Concepts] Observer Pattern

seops 2020. 3. 30. 23:12

[ 정의 ]


※ Observer Pattern이란?

 

me) Subject와 Observer들로 구성되며(일 대 다), 데이터를 포함한 객체가 변화하게 되면 Observer들에게 알려주는 패턴

 

- 한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체들에게 연락이 가고, 자동으로 내용이 갱신되는 방식으로 '일대다' 의존성을 정의

- 데이터의 주인은 Subject이며, Observer는 데이터가 변경되었을 때, Subject에서 갱신해 주기를 기다리는 입장이기 떄문에 의존성을 갖음

- 느슨하게 결합하는 디자인을 사용하면 변경 사항이 생겨도, 무난히 처리할 수 있는 유연한 객체지향 시스템을 구축할 수 있음 (객체 사이의 상호의존성 최소화)

 

Observer Pattern Class Diagram

 

 

[ 구현 ]


 Subject

public interface Subject {
    public void registerObserver(Observer o);
    public void unregisterObserver(Observer o);
    public void notifyObservers();
}


public class WeaterData implements Subject {
    private ArrayList observers;
    private float temperature;
    ...
    
    public WeatherData() {
        observers = new ArrayList();
    }
    
    public void registerObserver(Observer o) {
        observers.add(o);
    }
    
    public void unregisterObserver(Observer o) {
        int i = observers.indexOf(o);
        if (i >= 0) {
            observers.remove(i);
        }
    }
    
    public void notifyObservers() {
        for(int i = 0; i < observers.size(); i++) {
            Observer observer = (Observer) observers.get(i);
            observer.update(Data);
        }
    }
    
    ...
}

- Observer 객체들을 저장하기 위해, ArrayList를 추가

 

 Observer

public interface Observer {
    pubilc void update(Data data) {
}


public class CurrentConditionsDisplay implements Observer {
    private Subject weatherData;
    private Data data;
    
    public CurrentConditionsDisplay(Subject weatherData) {
        this.weatherData = weatherData;
        weatherData.registerObserver(this);
    }
    
    ....
}

 

 

[ 보충 ]


※ Java API > 내장 Observer Pattern

 - Interface Subject -> Class Observable 

 - Interface Observer -> Interface Observer

 

Observer Pattern in Java

 - ConcreteSubject 클래스가 Observable 클래스를 상속 받아야 함

 - Observer가 연락을 받는 방법으로는 2가지 방식 존재

  1) Push

   - Observer 인터페이스의 update 메소드 호출 시, 구체적인 인자를 통해 전달 받는 방식

   - update(int humidity, int degree)

 

  2) Pull

   - Observer 인터페이스의 update 메소드 호출 시, Observable과 Object 객체를 통해 전달 받는 방식

public void update(Observable obs, Object args) {
    if(obs instantod WeatherData) {
        WeatherData weatherData = (WeatherData) obs;
        this.temperature = weatherData.getTemperatrue();
        this.humidity = weatherData.getHumidity();
        display();
    }
}

 

 

주의 사항

 - Observer의 연락 순서에는 의존하면 안됨

   ~ 순서가 바뀐다고 해서 다른 결과가 나온다면, 그것은 '느슨한 결합'이라고 할 수 없음

   ~ 객체 사이의 상호 의존성 증가

 

 단점

 - Observable이 클래스이기 때문에, 서브 클래스를 만들어야 한다는 문제점 발생 ~ 재사용성의 제약이 생김

 - Observable 인터페이스라는 것이 없기 때문에, 자바에 내장된 Observer API와 맞는 클래스 구현 불가

 

 

[ 추가 ]


주의 사항

 - 삭제한 Subject들에 대한 무효 참조자를 계속 유지할 때가 있음

  ~ Subject의 삭제로 Observer가 무효 참조자를 갖게 되도록 만들면 안됨

 

 - 복잡한 갱신의 의미 구조를 캡슐화

  1) Subject와 Observer 간에 발생하는 관련성이 복잡하다면, 이들 관련성을 관리하는 별도의 객체를 만듦

  2) 예시

   - 연산의 수행으로 여러 개의 서로 관련된 주체를 변경해야 한다고 가정

   - 이때, 모든 Subject가 수정되고 나서 이 Subject의 Observer에게는 딱 한 번만 통보되어야 한다.

  3) 별도 객체(ChangeManager)는 아래 사항을 책임져야 함

   - Subject와 Observer를 Mapping하고, 이를 유지하는 인터페이스를 정의

   - Subject는 자신들의 Observer가 누구인지, Observer는 자신들의 Subject가 누구인지 관리할 필요 없음

   - Subject에게 요청이 있을 때, 모든 독립적 Observer 수정

 

Observer Pattern With ChangeManager

public interface ChangeManager {
    public abstract void register(Subject subject, Observer observer);
    public abstract void unregister(Subject subject, Observer observer);
    public abstract void notifyObservers(Subject subject);
}


public class ConcreteChangeManager implements ChangeManager {
    Map<Subject, List<Observer>> mapping;
    
    public ConcreteChangeManaer() {
        mapping = new HashMap<Subject, List<Observer>>();
    }
    
    @Override
    public void register(Subject subject, Observer observer) {
        if(mapping.containsKey(subject)) {
            mapping.get(subject).add(observer);
        } else {
            mapping.put(subject, new ArrayList<Observer>(Arrays.asList(observer)));
        }
    }
    
    @Override
    public void unregister(Subject subject, Observer observer) {
        if(mapping.containsKey(subject)) {
           if(mapping.get(subject).contains(observer)) {
               mapping.get(subject).remove(observer);
           }
        }
    }
    
    @Override
    public void notifyObservers(Subject subject) {
        for(Observer observer : mapping.get(subject)) {
            observer.update(subject);
        }
    }
}

 

 

[ 참고 (Reference) ]


1. Book > Head First Design Pattern

2. Book > GoF Design Pattern

3. Code >

https://github.com/csparpa/gof-design-patterns/tree/master/java/src/tk/csparpa/gofdp/observer/variants

 

csparpa/gof-design-patterns

Original GoF design patterns in multiple languages - csparpa/gof-design-patterns

github.com

 

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

[Concepts] Factory Method Pattern  (0) 2020.04.14
[Development] Observer Pattern  (0) 2020.03.30
Comments