๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
develop_kr/์ด๋ก 

๐Ÿ” ์˜ต์ €๋ฒ„ ํŒจํ„ด(Observer Pattern) ์™„๋ฒฝ ๊ฐ€์ด๋“œ

by JSsunday 2025. 7. 7.
728x90
๋ฐ˜์‘ํ˜•

๐Ÿ“– ์˜ต์ €๋ฒ„ ํŒจํ„ด์ด๋ž€?

์˜ต์ €๋ฒ„ ํŒจํ„ด(Observer Pattern)์€ ๊ฐ์ฒด ๊ฐ„์˜ ์ผ๋Œ€๋‹ค ์˜์กด์„ฑ์„ ์ •์˜ํ•˜๋Š” ํ–‰๋™ ๋””์ž์ธ ํŒจํ„ด์ž…๋‹ˆ๋‹ค. ํ•œ ๊ฐ์ฒด์˜ ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋  ๋•Œ, ๊ทธ ๊ฐ์ฒด์— ์˜์กดํ•˜๋Š” ๋ชจ๋“  ๊ฐ์ฒด๋“ค์ด ์ž๋™์œผ๋กœ ์•Œ๋ฆผ์„ ๋ฐ›๊ณ  ์—…๋ฐ์ดํŠธ๋˜๋Š” ๊ตฌ์กฐ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

์ด ํŒจํ„ด์€ ๋ฐœํ–‰-๊ตฌ๋…(Publish-Subscribe) ํŒจํ„ด์ด๋ผ๊ณ ๋„ ๋ถˆ๋ฆฌ๋ฉฐ, ๋А์Šจํ•œ ๊ฒฐํ•ฉ(Loose Coupling)์„ ํ†ตํ•ด ๊ฐ์ฒด ๊ฐ„์˜ ์ƒํ˜ธ์ž‘์šฉ์„ ํšจ์œจ์ ์œผ๋กœ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.

๐Ÿ—๏ธ ์˜ต์ €๋ฒ„ ํŒจํ„ด์˜ ๊ตฌ์กฐ

์˜ต์ €๋ฒ„ ํŒจํ„ด์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ฃผ์š” ๊ตฌ์„ฑ์š”์†Œ๋กœ ์ด๋ฃจ์–ด์ ธ ์žˆ์Šต๋‹ˆ๋‹ค:

๐ŸŽฏ Subject (์ฃผ์ œ)

  • ์˜ต์ €๋ฒ„๋“ค์˜ ๋ชฉ๋ก์„ ๊ด€๋ฆฌ
  • ์˜ต์ €๋ฒ„๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ œ๊ฑฐํ•˜๋Š” ๋ฉ”์„œ๋“œ ์ œ๊ณต
  • ์ƒํƒœ ๋ณ€๊ฒฝ ์‹œ ๋ชจ๋“  ์˜ต์ €๋ฒ„์—๊ฒŒ ์•Œ๋ฆผ

๐Ÿ‘๏ธ Observer (๊ด€์ฐฐ์ž)

  • Subject์˜ ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ๋ฐ›๊ธฐ ์œ„ํ•œ ์ธํ„ฐํŽ˜์ด์Šค ์ •์˜
  • ์—…๋ฐ์ดํŠธ ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ๋ณ€๊ฒฝ์‚ฌํ•ญ์— ๋ฐ˜์‘

๐Ÿข ConcreteSubject (๊ตฌ์ฒด์  ์ฃผ์ œ)

  • Subject ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„
  • ์‹ค์ œ ์ƒํƒœ๋ฅผ ์ €์žฅํ•˜๊ณ  ๋ณ€๊ฒฝ์‚ฌํ•ญ์„ ์˜ต์ €๋ฒ„๋“ค์—๊ฒŒ ํ†ต์ง€

๐Ÿ‘ค ConcreteObserver (๊ตฌ์ฒด์  ๊ด€์ฐฐ์ž)

  • Observer ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„
  • Subject์˜ ์ƒํƒœ ๋ณ€๊ฒฝ์— ๋Œ€ํ•œ ๊ตฌ์ฒด์ ์ธ ๋ฐ˜์‘ ์ •์˜

๐Ÿ’ป Java ์˜ˆ์ œ: ์ปดํ“จํ„ฐ ์„ฑ๋Šฅ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ

import java.util.ArrayList;
import java.util.List;

// Observer ์ธํ„ฐํŽ˜์ด์Šค
interface PerformanceObserver {
    void update(String component, double usage);
}

// Subject ์ธํ„ฐํŽ˜์ด์Šค
interface PerformanceSubject {
    void addObserver(PerformanceObserver observer);
    void removeObserver(PerformanceObserver observer);
    void notifyObservers();
}

// ConcreteSubject - ์ปดํ“จํ„ฐ ์„ฑ๋Šฅ ๋ชจ๋‹ˆํ„ฐ
class ComputerPerformanceMonitor implements PerformanceSubject {
    private List<PerformanceObserver> observers;
    private String currentComponent;
    private double currentUsage;
    
    public ComputerPerformanceMonitor() {
        this.observers = new ArrayList<>();
    }
    
    @Override
    public void addObserver(PerformanceObserver observer) {
        observers.add(observer);
        System.out.println("๐Ÿ”” ์ƒˆ๋กœ์šด ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ์ด ๋“ฑ๋ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค.");
    }
    
    @Override
    public void removeObserver(PerformanceObserver observer) {
        observers.remove(observer);
        System.out.println("โŒ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ์ด ํ•ด์ œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.");
    }
    
    @Override
    public void notifyObservers() {
        for (PerformanceObserver observer : observers) {
            observer.update(currentComponent, currentUsage);
        }
    }
    
    public void setPerformanceData(String component, double usage) {
        this.currentComponent = component;
        this.currentUsage = usage;
        System.out.println("๐Ÿ“Š " + component + " ์‚ฌ์šฉ๋ฅ : " + usage + "%");
        notifyObservers();
    }
}

// ConcreteObserver - CPU ์•Œ๋ฆผ ์‹œ์Šคํ…œ
class CPUAlert implements PerformanceObserver {
    private String name;
    
    public CPUAlert(String name) {
        this.name = name;
    }
    
    @Override
    public void update(String component, double usage) {
        if (component.equals("CPU") && usage > 80.0) {
            System.out.println("๐Ÿšจ [" + name + "] CPU ์‚ฌ์šฉ๋ฅ  ์œ„ํ—˜! " + usage + "% - ์ฆ‰์‹œ ํ™•์ธ ํ•„์š”");
        }
    }
}

// ConcreteObserver - ๋ฉ”๋ชจ๋ฆฌ ์•Œ๋ฆผ ์‹œ์Šคํ…œ
class MemoryAlert implements PerformanceObserver {
    private String name;
    
    public MemoryAlert(String name) {
        this.name = name;
    }
    
    @Override
    public void update(String component, double usage) {
        if (component.equals("Memory") && usage > 90.0) {
            System.out.println("โš ๏ธ [" + name + "] ๋ฉ”๋ชจ๋ฆฌ ๋ถ€์กฑ ๊ฒฝ๊ณ ! " + usage + "% - ๋ฉ”๋ชจ๋ฆฌ ์ •๋ฆฌ ๊ถŒ์žฅ");
        }
    }
}

// ConcreteObserver - ๋กœ๊ทธ ์‹œ์Šคํ…œ
class PerformanceLogger implements PerformanceObserver {
    @Override
    public void update(String component, double usage) {
        System.out.println("๐Ÿ“ [๋กœ๊ทธ] " + component + " ์‚ฌ์šฉ๋ฅ  ๊ธฐ๋ก: " + usage + "%");
    }
}

// ์‚ฌ์šฉ ์˜ˆ์ œ
public class ComputerMonitoringExample {
    public static void main(String[] args) {
        // Subject ์ƒ์„ฑ
        ComputerPerformanceMonitor monitor = new ComputerPerformanceMonitor();
        
        // Observer๋“ค ์ƒ์„ฑ ๋ฐ ๋“ฑ๋ก
        CPUAlert cpuAlert = new CPUAlert("์„œ๋ฒ„์‹ค ๊ด€๋ฆฌ์ž");
        MemoryAlert memoryAlert = new MemoryAlert("์‹œ์Šคํ…œ ๊ด€๋ฆฌ์ž");
        PerformanceLogger logger = new PerformanceLogger();
        
        monitor.addObserver(cpuAlert);
        monitor.addObserver(memoryAlert);
        monitor.addObserver(logger);
        
        System.out.println("\n=== ์ปดํ“จํ„ฐ ์„ฑ๋Šฅ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์ž‘ ===");
        
        // ์„ฑ๋Šฅ ๋ฐ์ดํ„ฐ ์—…๋ฐ์ดํŠธ
        monitor.setPerformanceData("CPU", 45.2);
        System.out.println();
        
        monitor.setPerformanceData("Memory", 67.8);
        System.out.println();
        
        monitor.setPerformanceData("CPU", 85.7); // CPU ๊ฒฝ๊ณ  ๋ฐœ์ƒ
        System.out.println();
        
        monitor.setPerformanceData("Memory", 94.3); // ๋ฉ”๋ชจ๋ฆฌ ๊ฒฝ๊ณ  ๋ฐœ์ƒ
    }
}

๐ŸŒŠ TypeScript ์˜ˆ์ œ: ๋ฐ”๋‹ค ์ƒํƒœ๊ณ„ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ

// Observer ์ธํ„ฐํŽ˜์ด์Šค
interface MarineObserver {
  update(location: string, temperature: number, depth: number): void;
}

// Subject ์ธํ„ฐํŽ˜์ด์Šค
interface MarineSubject {
  addObserver(observer: MarineObserver): void;
  removeObserver(observer: MarineObserver): void;
  notifyObservers(): void;
}

// ConcreteSubject - ํ•ด์–‘ ํ™˜๊ฒฝ ๋ชจ๋‹ˆํ„ฐ
class OceanEnvironmentMonitor implements MarineSubject {
  private observers: MarineObserver[] = [];
  private currentLocation: string = "";
  private currentTemperature: number = 0;
  private currentDepth: number = 0;

  addObserver(observer: MarineObserver): void {
    this.observers.push(observer);
    console.log("๐Ÿ  ์ƒˆ๋กœ์šด ํ•ด์–‘ ๊ด€์ธก์†Œ๊ฐ€ ๋“ฑ๋ก๋˜์—ˆ์Šต๋‹ˆ๋‹ค.");
  }

  removeObserver(observer: MarineObserver): void {
    const index = this.observers.indexOf(observer);
    if (index > -1) {
      this.observers.splice(index, 1);
      console.log("๐ŸŒŠ ํ•ด์–‘ ๊ด€์ธก์†Œ๊ฐ€ ํ•ด์ œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.");
    }
  }

  notifyObservers(): void {
    this.observers.forEach(observer => {
      observer.update(this.currentLocation, this.currentTemperature, this.currentDepth);
    });
  }

  setEnvironmentData(location: string, temperature: number, depth: number): void {
    this.currentLocation = location;
    this.currentTemperature = temperature;
    this.currentDepth = depth;
    
    console.log(`๐ŸŒŠ [${location}] ์ˆ˜์˜จ: ${temperature}°C, ์ˆ˜์‹ฌ: ${depth}m`);
    this.notifyObservers();
  }
}

// ConcreteObserver - ํ•ด์–‘ ์ƒ๋ฌผ ๋ณดํ˜ธ ์„ผํ„ฐ
class MarineLifeProtectionCenter implements MarineObserver {
  private centerName: string;

  constructor(centerName: string) {
    this.centerName = centerName;
  }

  update(location: string, temperature: number, depth: number): void {
    // ์ˆ˜์˜จ์ด ๋„ˆ๋ฌด ๋†’๊ฑฐ๋‚˜ ๋‚ฎ์œผ๋ฉด ๊ฒฝ๊ณ 
    if (temperature > 28 || temperature < 10) {
      console.log(`๐Ÿšจ [${this.centerName}] ${location} ์ง€์—ญ ์ˆ˜์˜จ ์ด์ƒ! ${temperature}°C - ํ•ด์–‘์ƒ๋ฌผ ๋ณดํ˜ธ ์กฐ์น˜ ํ•„์š”`);
    }
    
    // ๊นŠ์€ ๋ฐ”๋‹ค ์ƒ๋ฌผ ์„œ์‹์ง€ ๋ชจ๋‹ˆํ„ฐ๋ง
    if (depth > 1000) {
      console.log(`๐Ÿ™ [${this.centerName}] ${location} ์‹ฌํ•ด ์ƒ๋ฌผ ์„œ์‹์ง€ ๊ฐ์ง€ - ์ˆ˜์‹ฌ ${depth}m`);
    }
  }
}

// ConcreteObserver - ๊ธฐ์ƒ์ฒญ ํ•ด์–‘ ์˜ˆ๋ณดํŒ€
class WeatherMarineForecast implements MarineObserver {
  update(location: string, temperature: number, depth: number): void {
    // ์ˆ˜์˜จ ๋ณ€ํ™”์— ๋”ฐ๋ฅธ ๋‚ ์”จ ์˜ˆ๋ณด ์—…๋ฐ์ดํŠธ
    if (temperature > 25) {
      console.log(`โ˜€๏ธ [๊ธฐ์ƒ์ฒญ] ${location} ์ง€์—ญ ๊ณ ์ˆ˜์˜จ์œผ๋กœ ์ธํ•œ ํญํ’ ๊ฐ€๋Šฅ์„ฑ ๋ชจ๋‹ˆํ„ฐ๋ง ์ค‘`);
    } else if (temperature < 15) {
      console.log(`โ„๏ธ [๊ธฐ์ƒ์ฒญ] ${location} ์ง€์—ญ ์ €์ˆ˜์˜จ - ํ•œ๋ฅ˜ ์˜ํ–ฅ ๋ถ„์„ ์ค‘`);
    }
  }
}

// ConcreteObserver - ์–ด์—… ์ •๋ณด ์„ผํ„ฐ
class FishingInformationCenter implements MarineObserver {
  update(location: string, temperature: number, depth: number): void {
    // ์–ดํš๋Ÿ‰ ์˜ˆ์ธก์„ ์œ„ํ•œ ํ™˜๊ฒฝ ๋ถ„์„
    if (temperature >= 18 && temperature <= 24 && depth <= 200) {
      console.log(`๐ŸŽฃ [์–ด์—…์ •๋ณด์„ผํ„ฐ] ${location} ์ง€์—ญ ์ตœ์  ์–ด์—… ์กฐ๊ฑด - ์ˆ˜์˜จ ${temperature}°C, ์ˆ˜์‹ฌ ${depth}m`);
    } else if (depth > 500) {
      console.log(`๐Ÿฆˆ [์–ด์—…์ •๋ณด์„ผํ„ฐ] ${location} ์‹ฌํ•ด์–ด ์„œ์‹์ง€ - ํŠน์ˆ˜ ์–ด์—… ์žฅ๋น„ ํ•„์š”`);
    }
  }
}

// ConcreteObserver - ํ•ด์–‘ ๋ฐ์ดํ„ฐ ๋กœ๊ฑฐ
class OceanDataLogger implements MarineObserver {
  private logData: Array<{location: string, temperature: number, depth: number, timestamp: Date}> = [];

  update(location: string, temperature: number, depth: number): void {
    const logEntry = {
      location,
      temperature,
      depth,
      timestamp: new Date()
    };
    
    this.logData.push(logEntry);
    console.log(`๐Ÿ“Š [๋ฐ์ดํ„ฐ๋กœ๊ฑฐ] ํ•ด์–‘ ๋ฐ์ดํ„ฐ ์ €์žฅ๋จ - ${location}: ${temperature}°C, ${depth}m`);
  }

  getRecentLogs(count: number = 5): void {
    console.log(`\n๐Ÿ“ˆ ์ตœ๊ทผ ${count}๊ฐœ ํ•ด์–‘ ๋ฐ์ดํ„ฐ:`);
    this.logData.slice(-count).forEach((log, index) => {
      console.log(`${index + 1}. ${log.location} - ${log.temperature}°C, ${log.depth}m (${log.timestamp.toLocaleTimeString()})`);
    });
  }
}

// ์‚ฌ์šฉ ์˜ˆ์ œ
class MarineMonitoringExample {
  static run(): void {
    // Subject ์ƒ์„ฑ
    const oceanMonitor = new OceanEnvironmentMonitor();
    
    // Observer๋“ค ์ƒ์„ฑ ๋ฐ ๋“ฑ๋ก
    const protectionCenter = new MarineLifeProtectionCenter("์ œ์ฃผ ํ•ด์–‘๋ณดํ˜ธ์„ผํ„ฐ");
    const weatherForecast = new WeatherMarineForecast();
    const fishingCenter = new FishingInformationCenter();
    const dataLogger = new OceanDataLogger();
    
    oceanMonitor.addObserver(protectionCenter);
    oceanMonitor.addObserver(weatherForecast);
    oceanMonitor.addObserver(fishingCenter);
    oceanMonitor.addObserver(dataLogger);
    
    console.log("\n=== ๐ŸŒŠ ํ•ด์–‘ ํ™˜๊ฒฝ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์ž‘ ===");
    
    // ๋‹ค์–‘ํ•œ ํ•ด์–‘ ํ™˜๊ฒฝ ๋ฐ์ดํ„ฐ ์—…๋ฐ์ดํŠธ
    oceanMonitor.setEnvironmentData("์ œ์ฃผ ๊ทผํ•ด", 22.5, 150);
    console.log();
    
    oceanMonitor.setEnvironmentData("๋™ํ•ด ์‹ฌํ•ด", 8.2, 1200);
    console.log();
    
    oceanMonitor.setEnvironmentData("์„œํ•ด ์—ฐ์•ˆ", 29.1, 45);
    console.log();
    
    oceanMonitor.setEnvironmentData("๋‚จํ•ด ์™ธํ•ด", 19.8, 800);
    console.log();
    
    // ๋ฐ์ดํ„ฐ ๋กœ๊ทธ ํ™•์ธ
    dataLogger.getRecentLogs();
  }
}

// ์‹คํ–‰
MarineMonitoringExample.run();

โœ… ์˜ต์ €๋ฒ„ ํŒจํ„ด์˜ ์žฅ์ 

๐Ÿ”„ ๋А์Šจํ•œ ๊ฒฐํ•ฉ (Loose Coupling)

Subject์™€ Observer๋Š” ์„œ๋กœ์˜ ๊ตฌ์ฒด์ ์ธ ๊ตฌํ˜„์— ์˜์กดํ•˜์ง€ ์•Š๊ณ , ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ํ†ตํ•ด์„œ๋งŒ ์ƒํ˜ธ์ž‘์šฉํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“ˆ ํ™•์žฅ์„ฑ

์ƒˆ๋กœ์šด Observer๋ฅผ ์‰ฝ๊ฒŒ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ธฐ์กด ์ฝ”๋“œ๋ฅผ ์ˆ˜์ •ํ•˜์ง€ ์•Š๊ณ ๋„ ์‹œ์Šคํ…œ์„ ํ™•์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐ŸŽฏ ๋™์  ๊ด€๊ณ„ ์„ค์ •

๋Ÿฐํƒ€์ž„์— Observer๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ œ๊ฑฐํ•  ์ˆ˜ ์žˆ์–ด ์œ ์—ฐํ•œ ์‹œ์Šคํ…œ ๊ตฌ์„ฑ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.

๐Ÿ“ข ์ผ๋Œ€๋‹ค ํ†ต์‹ 

ํ•˜๋‚˜์˜ Subject๊ฐ€ ์—ฌ๋Ÿฌ Observer์—๊ฒŒ ๋™์‹œ์— ์•Œ๋ฆผ์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

โŒ ์˜ต์ €๋ฒ„ ํŒจํ„ด์˜ ๋‹จ์ 

๐ŸŒ ์„ฑ๋Šฅ ์˜ค๋ฒ„ํ—ค๋“œ

Observer๊ฐ€ ๋งŽ์„ ๊ฒฝ์šฐ ๋ชจ๋“  Observer์—๊ฒŒ ์•Œ๋ฆผ์„ ๋ณด๋‚ด๋Š” ๋ฐ ์‹œ๊ฐ„์ด ์†Œ์š”๋ฉ๋‹ˆ๋‹ค.

๐Ÿ” ๋””๋ฒ„๊น…์˜ ์–ด๋ ค์›€

Observer ์ฒด์ธ์ด ๋ณต์žกํ•ด์ง€๋ฉด ํ”„๋กœ๊ทธ๋žจ์˜ ํ๋ฆ„์„ ์ถ”์ ํ•˜๊ธฐ ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ’พ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜ ์œ„ํ—˜

Observer๋ฅผ ์ œ๋Œ€๋กœ ์ œ๊ฑฐํ•˜์ง€ ์•Š์œผ๋ฉด ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐Ÿ”„ ์ˆœํ™˜ ์ข…์†์„ฑ

Observer์™€ Subject ๊ฐ„์— ์ˆœํ™˜ ์ข…์†์„ฑ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๐ŸŽฏ ์–ธ์ œ ์‚ฌ์šฉํ•ด์•ผ ํ• ๊นŒ?

์˜ต์ €๋ฒ„ ํŒจํ„ด์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ƒํ™ฉ์—์„œ ์œ ์šฉํ•ฉ๋‹ˆ๋‹ค:

  • ๐Ÿ“Š ๋ชจ๋ธ-๋ทฐ ์•„ํ‚คํ…์ฒ˜: GUI ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ ์‹œ ํ™”๋ฉด ์—…๋ฐ์ดํŠธ
  • ๐Ÿ”” ์ด๋ฒคํŠธ ์‹œ์Šคํ…œ: ์‚ฌ์šฉ์ž ์•ก์…˜์ด๋‚˜ ์‹œ์Šคํ…œ ์ด๋ฒคํŠธ์— ๋Œ€ํ•œ ๋ฐ˜์‘
  • ๐Ÿ“ˆ ์‹ค์‹œ๊ฐ„ ๋ชจ๋‹ˆํ„ฐ๋ง: ์‹œ์Šคํ…œ ์ƒํƒœ๋‚˜ ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ ์ถ”์ 
  • ๐Ÿ”„ ์ƒํƒœ ๋™๊ธฐํ™”: ์—ฌ๋Ÿฌ ์ปดํฌ๋„ŒํŠธ ๊ฐ„์˜ ์ƒํƒœ ์ผ์น˜ ํ•„์š”
  • ๐Ÿ“ข ์•Œ๋ฆผ ์‹œ์Šคํ…œ: ํŠน์ • ์กฐ๊ฑด ๋ฐœ์ƒ ์‹œ ์—ฌ๋Ÿฌ ๋Œ€์ƒ์—๊ฒŒ ์•Œ๋ฆผ

๐Ÿš€ ์‹ค์ œ ํ™œ์šฉ ์‚ฌ๋ก€

1. ๐Ÿ’ป ์›น ๊ฐœ๋ฐœ

  • React์˜ ์ƒํƒœ ๊ด€๋ฆฌ: Redux, MobX ๋“ฑ์˜ ์ƒํƒœ ๊ด€๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ
  • DOM ์ด๋ฒคํŠธ: addEventListener๋ฅผ ํ†ตํ•œ ์ด๋ฒคํŠธ ์ฒ˜๋ฆฌ
  • WebSocket ํ†ต์‹ : ์‹ค์‹œ๊ฐ„ ๋ฐ์ดํ„ฐ ์—…๋ฐ์ดํŠธ

2. ๐Ÿ“ฑ ๋ชจ๋ฐ”์ผ ์•ฑ ๊ฐœ๋ฐœ

  • ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ: ๋ฐ์ดํ„ฐ ๋ณ€๊ฒฝ ์‹œ UI ์ž๋™ ์—…๋ฐ์ดํŠธ
  • ํ‘ธ์‹œ ์•Œ๋ฆผ: ์„œ๋ฒ„ ์ด๋ฒคํŠธ์— ๋”ฐ๋ฅธ ํด๋ผ์ด์–ธํŠธ ์•Œ๋ฆผ
  • ์„ผ์„œ ๋ฐ์ดํ„ฐ: GPS, ๊ฐ€์†๋„๊ณ„ ๋“ฑ์˜ ์„ผ์„œ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ

3. ๐Ÿข ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ์‹œ์Šคํ…œ

  • ๋กœ๊น… ์‹œ์Šคํ…œ: ๋‹ค์–‘ํ•œ ๋กœ๊ทธ ๋Œ€์ƒ์— ๋™์‹œ ๊ธฐ๋ก
  • ๋ชจ๋‹ˆํ„ฐ๋ง: ์‹œ์Šคํ…œ ๋ฉ”ํŠธ๋ฆญ ๋ณ€ํ™” ๊ฐ์ง€ ๋ฐ ์•Œ๋ฆผ
  • ์›Œํฌํ”Œ๋กœ์šฐ: ๋น„์ฆˆ๋‹ˆ์Šค ํ”„๋กœ์„ธ์Šค ๋‹จ๊ณ„๋ณ„ ์ฒ˜๋ฆฌ

๐Ÿ’ก ๊ตฌํ˜„ ํŒ

1. ๐Ÿ”’ Thread Safety

๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ๋Š” Observer ๋ชฉ๋ก ์ ‘๊ทผ ์‹œ ๋™๊ธฐํ™”๋ฅผ ๊ณ ๋ คํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

private final List<Observer> observers = 
    Collections.synchronizedList(new ArrayList<>());

2. ๐ŸŽฏ ํƒ€์ž… ์•ˆ์ „์„ฑ

์ œ๋„ค๋ฆญ์„ ํ™œ์šฉํ•˜์—ฌ ํƒ€์ž… ์•ˆ์ „์„ฑ์„ ๋†’์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

interface Observer<T> {
    void update(T data);
}

3. ๐Ÿ—‘๏ธ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ

WeakReference๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ฉ”๋ชจ๋ฆฌ ๋ˆ„์ˆ˜๋ฅผ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

private final List<WeakReference<Observer>> observers = new ArrayList<>();

๐ŸŽจ ๋งˆ๋ฌด๋ฆฌ

์˜ต์ €๋ฒ„ ํŒจํ„ด์€ ๊ฐ์ฒด ๊ฐ„์˜ ๋А์Šจํ•œ ๊ฒฐํ•ฉ์„ ํ†ตํ•ด ์œ ์—ฐํ•˜๊ณ  ํ™•์žฅ ๊ฐ€๋Šฅํ•œ ์‹œ์Šคํ…œ์„ ๊ตฌ์ถ•ํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ๊ฐ•๋ ฅํ•œ ๋””์ž์ธ ํŒจํ„ด์ž…๋‹ˆ๋‹ค. ํŠนํžˆ ์ด๋ฒคํŠธ ๊ธฐ๋ฐ˜ ํ”„๋กœ๊ทธ๋ž˜๋ฐ๊ณผ ์‹ค์‹œ๊ฐ„ ์‹œ์Šคํ…œ์—์„œ ๊ทธ ์ง„๊ฐ€๋ฅผ ๋ฐœํœ˜ํ•ฉ๋‹ˆ๋‹ค.

ํŒจํ„ด์„ ์ ์šฉํ•  ๋•Œ๋Š” ์‹œ์Šคํ…œ์˜ ๋ณต์žก์„ฑ๊ณผ ์„ฑ๋Šฅ์„ ๊ท ํ˜• ์žˆ๊ฒŒ ๊ณ ๋ คํ•˜์—ฌ, ์ ์ ˆํ•œ ์ƒํ™ฉ์—์„œ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. ์œ„์˜ ์˜ˆ์ œ๋“ค์„ ์ฐธ๊ณ ํ•˜์—ฌ ์—ฌ๋Ÿฌ๋ถ„๋งŒ์˜ ์ฐฝ์˜์ ์ธ ํ™œ์šฉ ๋ฐฉ๋ฒ•์„ ์ฐพ์•„๋ณด์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค!


 

728x90
๋ฐ˜์‘ํ˜•

๋Œ“๊ธ€