[디자인 패턴] 옵서버(Observer)
옵서버 패턴이란 상태의 변경이 발생했을 때, 구체적인 클래스에 의존하지 않고 변경을 통보하고자 할 때 유용한 패턴을 의미합니다.
옵서버 패턴 적용 전,
데이터의 변경이 일어나는 주체 클래스와 데이터의 변경을 통
보받아야하는 DataSheetView
ScoreRecord의 addScore(int score) 메서드가 호출되어 새로운 점수가 scores 리스트에 추가 되었을때 dataSheetView 객체의 update() 메서드를 직접 호출한다.
그러나 SoceRecord의 데이터를 다양한 형식으로 즉 다양한 View를 통해 보여주고 싶은 경우가 있을 것이다.
위와 같이 score을 MinMax 값을 보여주는 view로 추가하고 싶다면, ScoreRecord가 의존하는 view를 바꾸거나 추가해야 한다.
i) DataSheetView를 이용하는 것이 아니라 MinMaxView를 이용한다면
ii) 다양한 viewCount를 가진 DataSheetView와 MinMaxView를 함께 이용하고자 한다면
위의 i와 ii)의 상황 모두 ScoreRecord가 특정 view에게 통보하도록 고정되어 있기 때문에 View의 추가나 삭제가 발생하는 경우 ScoreRecord 클래스의 변경이 불가피하다 => OCP 위배
우리는 해당 문제를 해결하기 위해 옵저버 패턴을 활용 할 수 있다. 성적 출력 프로젝트에 옵저버 패턴을 적용한 다이어그램은 아래와 같다.
기존에는 ScoreRecord 에서 MinMaxView 와 DataSheetView 를 직접적으로 참조해서 데이터의 변경을 통보했던 반면,
패턴을 적용한 이후에는 추상클래스Subject 가 Observer 인터페이스를 참조하여 구체적인 Observer 클래스들을 통합하여 관리할 수 있도록 해줍니다.
Subject 클래스
concreteObserver 객체를 관리하는 요소
통보 대상인 Observer를 List로 보관하며, 통보 대상을 attach, detach를 통해 추가, 제거한다.
그리고 List 내 Observer들에게 데이터의 변경을 notifyObservers 메서드를 통해 일괄적으로 통보한다.
- ConcreteSubject에서 해당 내용을 구현하지 않고 굳이 Subject 추상 클래스를 두는 이유?
해당 예시에서는 ScoreRecord에 대한 내용만 존재하지만, 데이터 변경에 대한 통보가 필요한 여러 concreteSubject객체가 존재 할 수 있다. 이때 Observer 관리 및 통보 로직을 중복하여 구현할 필요성이 없기 때문에 Subject abstract에서 구현하여 concreteSubject가 상속 받도록 한다.
Observer 인터페이스
Subject가 ConcreteObserver에 의존하지 않도록 Observer 인터페이스를 구현한다.
Observer의 update 메서드를 호출함으로써 성적 변경을 ConcreteObserver에게 통보한다.
Concrete Observer (MinMaxView, DataSheetView )
ConcreteSubject의 변경을 통보받는 클래스
ConcreteSubject의 변경을 통보받는 클래스 . Observer 인터페이스의 update 메서드를 구현함으로써 변경을 통보받음.
변경된 데이터는 ConcreteSubject의 getstate(getScore) 메서드를 호출함으로써 변경을 조회함.
Concrete Subject (ScoreBoard)
변경 관리 대상이 되는 데이터가 있는 클래스
데이터 변경을 위한 메서드인 setState에서
자신의 데이터를 변경하고
notifyObservers 메서드를 호출하여ConcreteObserver에 변경을
통보함.
setState() 로 데이터의 변경이 발생했을 때 Subject의 notifyObservers가 호출되면서 Collection에 담긴 구체적인 Observer 들에게 update()를 통보하고, 각 관찰자 객체들을 데이터를 제 조회하여 view에 반영함.