일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- JavaScript
- 인프콘 2024
- 단기개발자코스
- 빈 충돌
- 항해99
- 커스텀 헤더
- Python
- @FeignClient
- infcon 2024
- 프로그래머스
- 취업리부트코스
- 개발자부트캠프추천
- 코딩테스트 준비
- TiL
- 전략패턴 #StrategyPattern #디자인패턴
- KPT회고
- 1주일회고
- 99클럽
- 파이썬
- 디자인패턴
- 프로그래머스 이중우선순위큐
- 구글 OAuth login
- Spring multimodule
- jwttoken
- 디자인 패턴
- jwt
- DesignPattern
- 빈 조회 2개 이상
- 개발자 취업
- spring batch 5.0
- Today
- Total
m1ndy5's coding blog
옵저버 패턴(Observer Pattern) 본문
옵저버 패턴의 정의
옵서버 패턴은 객체의 상태 변화를 관찰하는 관찰자들, 즉 옵저버들의 목록을 객체에 등록하여 상태 변화가 있을 때마다 메서드 등을 통해 객체가 직접 목록의 각 옵저버에게 통지하도록 하는 디자인 패턴이다. 주로 분산 이벤트 핸들링 시스템을 구현하는 데 사용된다.(출처: 위키백과)
즉, 한 객체의 상태가 바뀌면 그 객체에 의존하는 다른 객체들에게 연락이가고 내용이 갱신되는 일대다 의존성을 뜻한다.
상태를 저장하고 있는 객체를 Subject, 갱신된 값들을 받는 객체들을 Observer로 보면된다.
보통 Subject Interface와 Observer Interface로 구현한다
public interface Subject{
// Observer 등록
public void registerObserver(Observer o);
// 등록된 Observer 삭제
public void removeObserver(Observer o);
// 값이 변경되면 Observers에게 알림
public void nofifyObservers();
}
public interface Observer{
public void update();
}
옵저버 패턴 이해
옵저버 패턴은 유튜브 채널을 구독하는 것과 비슷하다고 생각하면 되는데
시청자가 유튜버를 구독하면 (알림설정이 되어있다는 전제)
새로운 동영상을 올리게 되면 시청자에게 새로운 동영상이 올라왔다는 알림이 가고 시청자는 새로운 동영상을 시청한다.
이 때 더이상 알림을 받고싶지 않다면 구독을 해지하고 새로운 동영상들을 보지 않을 수 있다. (해지하면 못본다는 전제)
한 유튜버는 여러 시청자로부터 구독을 당할 수도 해지를 당할 수도 있다.
여기서 유튜버는 Subject, 구독자들은 Observer라고 생각하면 된다.
Subject가 Observer에게 데이터를 보내는 Push 방식
Observer가 Subject로부터 갱신된 데이터를 받는데는 두가지 방법이 있다.
첫 번째로 값이 갱신될 때마다 Subject가 Observer에게 야 나 값바꼈어 가져가 하고 보내주는 방법이 있고
Observer가 야 너 값 바꼈어?? 나 좀 가져간다하고 Subject의 getter를 사용해서 값을 가져오는 방법이 있다.
일단 Push 방식을 알아보자
public interface Subject{
// Observer 등록
public void registerObserver(Observer o);
// 등록된 Observer 삭제
public void removeObserver(Observer o);
// 값이 변경되면 Observers에게 알림
public void nofifyObservers();
}
public interface Observer{
public void update(float temp, float humidity, float pressure);
}
// Subject interface를 implements한 WeatherData
// 온도, 습도, 기압정보를 가지고 있다.
public class WeatherData implements Subject{
// 이 subject를 구독한 구독자들(?) 여러명이 구독할 수 있기 때문에 list로 표현
private List<Observer> observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData(){
observers = new ArrayList<Observer>();
}
// Observer 등록
public void registerObserver(Observer o){
observers.add(o);
}
// Observer 삭제
public void removeObserver(Observer o){
observers.remove(o);
}
// Observers에게 알리기
public void notifyObservers(){
for (Observer observer : observers){
observer.update(temperature, humidity, pressure);
}
}
public void measurementsChanged(){
notifyObservers();
}
public void setMeasurements(float temp, float humid, float press){
this.temperature = temp;
this.humidity = humid;
this.pressure = press;
measurementsChanged(); // setter가 호출되면 값이 변경되었음을 알리는 메서드
}
}
// 날씨정보를 보여주는 디스플레이, Observer interface를 implements하고 있음
public class CurrentDisplay implements Observer{
private float temperature;
private float humidity;
private WeatherData weatherData;
// 생성될 때 weatherData에 observer로 등록
public CurrentDisplay(WeatherData weatherData){
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
public void update(float temp, float humid, float press){
this.temperature = temp;
this.humidity = humid;
}
public void display(){
// 온.습도 정보 디스플레이
}
}
public class Main{
public static void main(String[] args){
WeatherData weatherData = new WeatherData();
CurrentDisplay current = new CurrentDisplay(weatherData);
weatherData.setMeasurements(1, 1, 1); // setter를 호출하면 구독한 옵저버의 update 메서드가 실행되면서 값 갱신
}
}
이렇게 했을 때 한가지의 안좋은 점은 Observer interface의 update 메서드에 어떤 값이 필요할 때마다 파라미터로 넣어주어야하는데 몇몇 값이 필요없는 observer들도 다 값들을 모두 받게 된다.
그럼 이 값들을 update의 매개변수로 보내주는 게 아니라 getter 메서드로 가져온다면?
Observer가 Subject로부터 값을 가져오는 Pull 방식
public interface Observer{
public void update();
}
public class WeatherData implements Subject{
private List<Observer> observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData() {
observers = new ArrayList<Observer>();
}
public void registerObserver(Observer o){
observers.add(o);
}
public void removeObserver(Observer o){
observers.remove(o);
}
public void notifyObservers(){
for (Observer observer : observers){
// 이전과는 다르게 파라미터로 값을 전달하지 않는다.
observer.update();
}
}
public void measurementsChanged(){
notifyObservers();
}
public void setMeasurements(float temperature, float humidity, float pressure){
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged(); //setter가 호출되면 Observers에게 변경된 값들을 전달
}
// getter를 만들어 주었다.
public void getTemperature(){
return this.temperature;
}
public void getHumidity(){
return this.humidity;
}
public void getPressure(){
return this.pressure;
}
}
public class CurrentDisplay implements Observer{
private float temperature;
private float humidity;
private WeatherData weatherData;
public CurrentConditionsdisplay(WeatherData weatherData){
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
//getter를 사용해서 값을 가져옴
public void update(){
this.temperature = weatherData.getTemperature();
this.humidity = weatherData.getHumidity();
}
public void display(){
System.out.println("현재 상태: 온도 " + temperature + "F, 습도 " + humidity + "%");
}
}
public class Weatherstation{
public static void main(String[] args){
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
weatherData.setMeasurements(80, 65, 30.4f);
// setter를 호출하게 되면 구독한 옵저버의 update메서드가 실행되면서 값이 변경
}
}
Observer가 원하는 내용만 골라서 가져올 수 있으므로 pull 방법을 사용하면 확장성이 더 좋아진다.
'백엔드 with java > Design Pattern' 카테고리의 다른 글
싱글톤(Singleton) feat. 스프링 (0) | 2023.12.04 |
---|---|
추상 팩토리 패턴(Abstract Factory Pattern) (0) | 2023.11.26 |
팩토리 메소드 패턴(Factory Method Pattern) (0) | 2023.11.26 |
데코레이터 패턴(Decorator Pattern) (1) | 2023.11.23 |
전략 패턴(Strategy Pattern) (0) | 2023.11.21 |