객체가 특정 객체 상태 변화를 감지하고 알림을 받는 패턴.
발생(publish) - 구독(subscribe) 패턴을 구현할 수 있다.
객체의 상태가 변경되면 Observer 의존하고 있는 객체에 업데이트된 상태를 알려주며,
일대다(one-to-many) 의존성 정의이다.
interface Observer {
// update 함수의 생성자를 통해
// 알려주고 싶은 상태를 생성자에 정의한다.
fun update(temp: Float, humidity: Float, pressure: Float)
}
/**
* 옵저버를 등록, 제거, 알림 기능을 제공하는 인터페이스이다.
* 옵저버 패턴은 구독을하고 해제하는 함수를 항상 만들어 두어야 하며,
* 필요가 없는 시점에 해제하지 않으면 메모리릭이 발생하기 때문에 사용하지 않는다면,
* 꼭 해제를 명시적으로 해제를 시켜주어야 한다.
* notifyObservers() 함수를 통해 구독된 옵저버 모두에게 변경된 상태를 알려 준다.
*/
interface Subject {
fun registerObserver(o: Observer)
fun removeObserver(o: Observer)
fun notifyObservers()
}
옵저버 인터페이스와 옵저버를 등록하는 인터페이스를 만들었다.
다음으로는 Subject 정의하는 클래스를 만들어 보자.
class WeatherData : Subject {
private var observers: ArrayList<Observer> = arrayListOf()
private var temperature: Float = 0f
private var humidity: Float = 0f
private var pressure: Float = 0f
override fun registerObserver(o: Observer) {
observers.add(o)
}
override fun removeObserver(o: Observer) {
observers.remove(o)
}
override fun notifyObservers() {
observers.forEach {
it.update(temperature, humidity, pressure)
}
}
fun measurementsChanged() {
notifyObservers()
}
fun setMeasurements(temperature: Float, humidity: Float, pressure: Float) {
this.temperature = temperature
this.humidity = humidity
this.pressure = pressure
measurementsChanged()
}
}
Subject
인터페이스를 등록한다.ArrayList<Observer>
생성한다.notifyObservers()
호출하여 구독하고 있는 사용자에게 알려준다.registerObserver(Observer)
함수를 통해 ArrayList 에 구독자 정보를 저장하고 notifyObservers()
함수를 통해 ArrayList 에 저장되어 있는 모든 Observer 객체에게 데이터가 변경되 었다고 알려준다.
더 이상 구독된 정보를 받기를 원하지 않는 경우 또는 옵저버를 사용하지 않는 경우에 removeObserver(Observer)
함수를 통해 메모리에서 삭제한다.
class ForecastDisplay(
weatherData: WeatherData
) : Observer, DisplayElement {
private var currentPressure = 29.92f
private var lastPressure: Float = 0f
init {
weatherData.registerObserver(this)
}
override fun display() {
println("Forecast: ")
if (currentPressure > lastPressure) {
println("Improving weather on the way!")
} else if (currentPressure == lastPressure) {
println("More of the same")
} else if (currentPressure < lastPressure) {
println("Watch out for cooler, rainy weather")
}
}
override fun update(temp: Float, humidity: Float, pressure: Float) {
lastPressure = currentPressure
currentPressure = pressure
display()
}
}
Subject
가 만들어져 있는 클래스를 받는다.Observer
인터페이스를 상속하여 update()
함수를 정의한다.init
함수를 통해 구독 요청을 보낸다.notifyObservers()
함수가 호출 되면 update()
정의해둔 로직이 실행 되어 데이터의 상태가 변경 된다.fun main() {
val weatherData: WeatherData = WeatherData()
val currentDisplay = CurrentConditionsDisplay(weatherData)
val statisticsDisplay = StatisticsDisplay(weatherData)
val forecastDisplay = ForecastDisplay(weatherData)
println("첫 번째 데이터")
weatherData.setMeasurements(85f, 65f, 30.4f)
println("두 번째 데이터")
weatherData.setMeasurements(82f, 70f, 29.2f)
println("세 번째 데이터")
weatherData.setMeasurements(78f, 90f, 29.2f)
weatherData.removeObserver(forecastDisplay)
println("\nForecastDisplay 구독 취소 후 데이터")
weatherData.setMeasurements(62f, 90f, 28.1f)
}
Subject
생성하는 WeatherData
클래스를 초기화 한다.Observer
상속되어 있는 클래스를 초기화 한다.setMeasurements()
함수를 통해 구독자에게 데이터가 변경되었음을 알려준다.forecastDisplay
객체의 구독을 제거한다.ForecastDisplay
구독을 취소 후 데이터를 변경하면,
기존에 CurrentConditionsDisplay
, StatisticsDisplay
의 데이터만 변경되고
ForecastDisplay
는 더 이상 데이터 변화를 감지할 수 없다.