μΌ | μ | ν | μ | λͺ© | κΈ | ν |
---|---|---|---|---|---|---|
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 |
29 | 30 |
- νν΄νλ¬μ€ νκΈ°
- μμ± ν¨ν΄
- fanout on read
- OOP
- νΌλ ꡬν
- μμ°¨μ§ν₯
- νν΄νλ¬μ€λ°±μλ
- νν΄ λ°±μλ
- push model
- νν΄νλ¬μ€
- νν΄νλ¬μ€ νκ³
- fanout on write
- νν
- νν΄+
- λΉ μ€μ½ν
- νν΄νλ¬μ€νκΈ°
- νν΄ νκΈ°
- λμμΈ ν¨ν΄
- TDD
- νν λ°±μλ
- νλ‘ν νμ λΉ
- μ±κΈν€ λΉ
- λ°μ΄ν° 쿼리
- νν΄νλ¬μ€ λ°±μλ
- νν΄
- νν΄ νλ¬μ€ νκΈ°
- pull model
- κΈ°λ₯ ν μ€νΈ
- API Aggregation
- νν νκΈ°
- Today
- Total
deVlog
[λμμΈ ν¨ν΄] νμ ν¨ν΄ - Observer Pattern (μ΅μ λ² ν¨ν΄) λ³Έλ¬Έ
[λμμΈ ν¨ν΄] νμ ν¨ν΄ - Observer Pattern (μ΅μ λ² ν¨ν΄)
μλ£¨λ° 2025. 4. 2. 22:12λͺ©μ°¨
π κ°μ
μ΅μ λ² ν¨ν΄(Observer Pattern)μ κ°μ²΄μ μν λ³νλ₯Ό κ΄μ°°νλ κ΄μ°°μλ€(μ΅μ λ²λ€)μκ² μλμΌλ‘ ν΅μ§νλ λμμΈ ν¨ν΄μ΄λ€. μ¦, ν κ°μ²΄μ μνκ° λ³νλ©΄ κ·Έ κ°μ²΄μ μμ‘΄νλ λ€λ₯Έ κ°μ²΄λ€μκ² μλμΌλ‘ μλ¦Όμ΄ κ°κ³ μμ λ μ λ°μ΄νΈλλ 1:N μμ‘΄μ±μ μ μνλ€.
νΉμ§
- λ°ν(Publish)-ꡬλ (Subscribe) λͺ¨λΈλ‘λ μλ €μ Έ μλ€.
- λμ¨ν κ²°ν©(Loose Coupling) ꡬ쑰λ₯Ό λ§λ€μ΄ κ°μ²΄ κ° μμ‘΄μ±μ μ΅μννλ€.
- λΆμ° μ΄λ²€νΈ νΈλ€λ§ μμ€ν μ ꡬννλ λ° μ΄μμ μ΄λ€.
π©π»π» μ½λλ‘ μμ보μ
λ μ¨ μ 보λ₯Ό μμ§νκ³ λ€μν λμ€νλ μ΄μ μ λ°μ΄νΈνλ μμ λ₯Ό ν΅ν΄ μ΅μ λ² ν¨ν΄μ μ΄ν΄λ³΄μ.
// 1. μ΅μ λ² μΈν°νμ΄μ€ (ꡬλ
μ)
interface Observer {
void update(float temperature, float humidity, float pressure);
}
// 2. μ£Όμ (Subject) μΈν°νμ΄μ€ (λ°νμ)
interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObservers();
}
// 3. ꡬ체μ μΈ μ£Όμ (ConcreteSubject) ν΄λμ€
class WeatherData implements Subject {
private List<Observer> observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData() {
observers = new ArrayList<>();
}
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
int i = observers.indexOf(o);
if (i >= 0) {
observers.remove(i);
}
}
@Override
public void notifyObservers() {
for (Observer observer : observers) {
observer.update(temperature, humidity, pressure);
}
}
// κΈ°μ μΈ‘μ κ°μ΄ κ°±μ λλ©΄ μ΅μ λ²λ€μκ² μλ¦°λ€
public void measurementsChanged() {
notifyObservers();
}
// μλ‘μ΄ μΈ‘μ κ°μΌλ‘ κ°±μ
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
}
// 4. ꡬ체μ μΈ μ΅μ λ²(ConcreteObserver) ν΄λμ€λ€
class CurrentConditionsDisplay implements Observer {
private float temperature;
private float humidity;
private Subject weatherData;
public CurrentConditionsDisplay(Subject weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
@Override
public void update(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
display();
}
public void display() {
System.out.println("νμ¬ λ μ¨ μν: μ¨λ " + temperature + "°C, μ΅λ " + humidity + "%");
}
}
class StatisticsDisplay implements Observer {
private float maxTemp = 0.0f;
private float minTemp = 200;
private float tempSum = 0.0f;
private int numReadings = 0;
private Subject weatherData;
public StatisticsDisplay(Subject weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
@Override
public void update(float temperature, float humidity, float pressure) {
tempSum += temperature;
numReadings++;
if (temperature > maxTemp) {
maxTemp = temperature;
}
if (temperature < minTemp) {
minTemp = temperature;
}
display();
}
public void display() {
System.out.println("λ μ¨ ν΅κ³: νκ· /μ΅κ³ /μ΅μ μ¨λ = " + (tempSum / numReadings) + "/" + maxTemp + "/" + minTemp);
}
}
class ForecastDisplay implements Observer {
private float currentPressure = 29.92f;
private float lastPressure;
private Subject weatherData;
public ForecastDisplay(Subject weatherData) {
this.weatherData = weatherData;
weatherData.registerObserver(this);
}
@Override
public void update(float temperature, float humidity, float pressure) {
lastPressure = currentPressure;
currentPressure = pressure;
display();
}
public void display() {
System.out.print("μΌκΈ° μ보: ");
if (currentPressure > lastPressure) {
System.out.println("λ μ¨κ° μ’μμ§κ³ μμ΅λλ€!");
} else if (currentPressure == lastPressure) {
System.out.println("μ§κΈκ³Ό λΉμ·ν κ² κ°μ΅λλ€.");
} else {
System.out.println("λ μμνκ³ λΉκ° μ¬ κ² κ°μ΅λλ€.");
}
}
}
// 5. ν΄λΌμ΄μΈνΈ
public class ObserverPatternExample {
public static void main(String[] args) {
// κΈ°μ λ°μ΄ν° κ°μ²΄ μμ± (μ£Όμ )
WeatherData weatherData = new WeatherData();
// λμ€νλ μ΄ κ°μ²΄λ€ μμ± (μ΅μ λ²λ€)
CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay(weatherData);
StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);
ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);
// κΈ°μ λ°μ΄ν° μ€μ (μ΄κ²μ΄ μ΅μ λ²λ€μκ² μλμΌλ‘ ν΅μ§λ¨)
System.out.println("첫 λ²μ§Έ κΈ°μ λ°μ΄ν° μ
λ°μ΄νΈ:");
weatherData.setMeasurements(27, 65, 30.4f);
System.out.println("\nλ λ²μ§Έ κΈ°μ λ°μ΄ν° μ
λ°μ΄νΈ:");
weatherData.setMeasurements(28, 70, 29.2f);
System.out.println("\nμΈ λ²μ§Έ κΈ°μ λ°μ΄ν° μ
λ°μ΄νΈ:");
weatherData.setMeasurements(26, 90, 29.3f);
// μ΅μ λ² μ κ±° μμ
weatherData.removeObserver(forecastDisplay);
System.out.println("\nμΌκΈ° μ보 μ κ±° ν μ
λ°μ΄νΈ:");
weatherData.setMeasurements(25, 80, 30.6f);
}
}
- Observer μΈν°νμ΄μ€λ λͺ¨λ μ΅μ λ²κ° ꡬνν΄μΌ νλ update() λ©μλλ₯Ό μ μνλ€.
- Subject μΈν°νμ΄μ€λ μ΅μ λ²μ λ±λ‘, μ κ±°, ν΅μ§ λ©μλλ₯Ό μ μνλ€.
- WeatherData ν΄λμ€λ Subjectλ₯Ό ꡬννκ³ κΈ°μ λ°μ΄ν°κ° λ³κ²½λ λ λ±λ‘λ λͺ¨λ μ΅μ λ²μκ² μλ¦°λ€.
- CurrentConditionsDisplay, StatisticsDisplay, ForecastDisplay ν΄λμ€λ Observerλ₯Ό ꡬννμ¬ λ μ¨ λ°μ΄ν°κ° μ λ°μ΄νΈλ λλ§λ€ κ°μμ λ°©μμΌλ‘ μ 보λ₯Ό νμνλ€.
βοΈ μ₯/λ¨μ
β μ₯μ
- λμ¨ν κ²°ν©(Loose Coupling)
- μ£Όμ (Subject)λ μ΅μ λ²(Observer)μ λν ꡬ체μ μΈ ν΄λμ€λ₯Ό μ νμκ° μλ€.
- μ΅μ λ²λ€μ΄ μ΄λ€ ν΄λμ€μΈμ§, 무μμ νλμ§ λͺ°λΌλ λλ€λ κ²μ΄ ν΅μ¬μ΄λ€.
- μ΄λ‘ μΈν΄ μμ€ν μ μ μ°μ±κ³Ό μ¬μ¬μ©μ±μ΄ ν₯μλλ€.
- κ°λ°©/νμ μμΉ(OCP) μ€μ
- κΈ°μ‘΄ μ½λλ₯Ό μμ νμ§ μκ³ λ μλ‘μ΄ μ΅μ λ² ν΄λμ€λ₯Ό μΆκ°ν μ μλ€.
- μ: μλ‘μ΄ λͺ¨λ°μΌ μ± λμ€νλ μ΄λ₯Ό μΆκ°νλλΌλ WeatherData ν΄λμ€λ λ³κ²½ν νμκ° μλ€.
- λ°νμμ κ°μ²΄ κ° κ΄κ³ λ³κ²½ κ°λ₯
- μ΅μ λ²λ μΈμ λ μ§ λμ μΌλ‘ μΆκ°νκ±°λ μ κ±°ν μ μλ€.
- μ΄λ μ€ν μ€μΈ μμ€ν μ λμμ μ μ°νκ² λ°κΏ μ μκ² ν΄μ€λ€.
- 1:N μμ‘΄μ± μ²λ¦¬μ μ ν©
- ν κ°μ²΄μ λ³κ²½μ΄ λ€λ₯Έ μ¬λ¬ κ°μ²΄μ μν₯μ λ―ΈμΉ λ μ μ©νλ€.
- MVC(Model-View-Controller) μν€ν μ²μμ Modelκ³Ό Viewμ κ΄κ³λ₯Ό ꡬνν λ μμ£Ό μ¬μ©λλ€.
β λ¨μ
- μμΈ‘νκΈ° μ΄λ €μ΄ μ
λ°μ΄νΈ μμ
- λ±λ‘λ μμμ λ°λΌ μ΅μ λ²κ° μ λ°μ΄νΈλλ―λ‘, νΉμ μμμ μμ‘΄νλ©΄ λ¬Έμ κ° λ°μν μ μλ€.
- μ΅μ λ² κ°μ μμ‘΄μ±μ΄ μμ κ²½μ° μμμΉ λͺ»ν λμμ΄ λ°μν μ μλ€.
- λ©λͺ¨λ¦¬ λμ κ°λ₯μ±
- μ΅μ λ² λ±λ‘ ν λͺ μμ μΌλ‘ μ κ±°νμ§ μμΌλ©΄ λ©λͺ¨λ¦¬ λμκ° λ°μν μ μλ€.
- νΉν μλ°μ κ°μ μΈμ΄μμ μ΅μ λ²κ° λ μ΄μ νμνμ§ μμ λ μ°Έμ‘°λ₯Ό ν΄μ ν΄μΌ νλ€.
- λΆνμν μ
λ°μ΄νΈ
- λͺ¨λ μ΅μ λ²μκ² νμ ν΅μ§νλ―λ‘ μΌλΆ μ΅μ λ²μκ²λ νμνμ§ μμ μ λ°μ΄νΈκ° μ λ¬λ μ μλ€.
- μ΄λ μ±λ₯ μ νλ₯Ό μ΄λν μ μλ€.
- 볡μ‘ν λλ²κΉ
- λΉλκΈ° λ°©μμΌλ‘ μ΅μ λ²λ₯Ό μ λ°μ΄νΈνλ©΄ λλ²κΉ μ΄ μ΄λ €μμ§ μ μλ€.
- μ¬λ¬ μ΅μ λ²κ° μλ‘ λ€λ₯Έ μ€λ λμμ μ€νλλ©΄ λμμ± λ¬Έμ κ° λ°μν μ μλ€.
π μ 리
μ΅μ λ² ν¨ν΄μ κ°μ²΄ κ°μ μΌλλ€ μμ‘΄ κ΄κ³λ₯Ό μ μνμ¬ ν κ°μ²΄μ μνκ° λ³κ²½λλ©΄ μμ‘΄νλ λͺ¨λ κ°μ²΄μκ² μλμΌλ‘ ν΅μ§λκ³ μ λ°μ΄νΈλλ ν¨ν΄μ΄λ€.
μ΄ ν¨ν΄μ λμ¨ν κ²°ν©μ ν΅ν΄ μ μ°μ±μ λμ΄κ³ , λ°νμμ κ°μ²΄ κ°μ κ΄κ³λ₯Ό λμ μΌλ‘ λ°κΏ μ μκ² ν΄μ€λ€. νμ§λ§ μ λ°μ΄νΈ μμ μμΈ‘μ μ΄λ €μ, λ©λͺ¨λ¦¬ λμ κ°λ₯μ±, λΆνμν μ λ°μ΄νΈ, λλ²κΉ μ 볡μ‘μ± λ±μ λ¨μ μ΄ μλ€.
β μΈμ μ¬μ©νλ©΄ μ’μκΉ?
- ν κ°μ²΄μ λ³νκ° λ€λ₯Έ μ¬λ¬ κ°μ²΄μ μν₯μ λ―ΈμΉ λ
- κ°μ²΄ κ°μ λμ¨ν κ²°ν©μ΄ νμν λ
- μ΄λ€ μ΄λ²€νΈκ° λ°μνμ λ λ€μν κ°μ²΄λ€μ΄ λ€λ₯Έ λ°©μμΌλ‘ λ°μν΄μΌ ν λ
- μ€μκ° λ°μ΄ν° μ μ‘μ΄ νμν λΆμ° μμ€ν μμ
- MVC μν€ν μ²μμ λͺ¨λΈκ³Ό λ·°μ κ΄κ³λ₯Ό ꡬνν λ
β μΈμ νΌν΄μΌ ν κΉ?
- μ΅μ λ² κ°μ 볡μ‘ν μμ‘΄μ±μ΄ μμ λ
- μ λ°μ΄νΈ μμκ° μ€μν λ
- λΆνμν μλ¦Όμ΄ μ±λ₯ λ¬Έμ λ₯Ό μΌμΌν¬ μ μμ λ
- λ©λͺ¨λ¦¬ μ¬μ©λμ΄ μ€μν μ νλ νκ²½μμ
π‘ μλ°μ λ΄μ₯ μ΅μ λ² ν¨ν΄
Javaμμλ java.util.Observable ν΄λμ€μ java.util.Observer μΈν°νμ΄μ€λ₯Ό ν΅ν΄ μ΅μ λ² ν¨ν΄μ μ§μνμΌλ, Java 9λΆν° Deprecatedλμλ€. λμ λ€μκ³Ό κ°μ λμμ μ¬μ©ν μ μλ€:
- PropertyChangeListener
- java.beans ν¨ν€μ§μ PropertyChangeSupportμ PropertyChangeListenerλ₯Ό μ¬μ©
- μμ± κ°μ λ³κ²½μ κ°μ§νκ³ μλ¦Όμ 보λ΄λ λ° μ μ©
- Flow API (Java 9+)
- java.util.concurrent.Flowμμ 리μ‘ν°λΈ νλ‘κ·Έλλ°μ μ§μ
- Publisher, Subscriber, Subscription μΈν°νμ΄μ€λ₯Ό μ 곡
- Event Listener
- Swing, JavaFX λ± GUI νλ μμν¬μμ μ¬μ©λλ μ΄λ²€νΈ 리μ€λ
- μ¬μ©μ μΈν°νμ΄μ€ μ΄λ²€νΈ μ²λ¦¬μ μ ν©
π μ€μ μ¬μ© μ¬λ‘
- GUI μμ€ν : λ²νΌ ν΄λ¦, ν€λ³΄λ μ λ ₯κ³Ό κ°μ μ¬μ©μ μ΄λ²€νΈ μ²λ¦¬
- μ΄λ²€νΈ κ΄λ¦¬ μμ€ν : μ΄λ²€νΈ λ°μ μ μ¬λ¬ νΈλ€λ¬μκ² ν΅μ§
- λ΄μ€ λ°ν-ꡬλ μλΉμ€: μ λ΄μ€ λ°ν μ ꡬλ μμκ² μλ¦Ό
- μμ λ―Έλμ΄ μλ¦Ό μμ€ν : μ νλ λ°μ μ μ¬μ©μμκ² μλ¦Ό
- μ€μκ° λͺ¨λν°λ§ μμ€ν : μμ€ν μν λ³νλ₯Ό μ¬λ¬ λͺ¨λν°λ§ λꡬμ μ λ¬