비트를 쪼개는 개발자

allen321@naver.com

C#

C# [디자인 패턴] - 옵저버 패턴(Observer Pattern)

MozarTnT 2024. 10. 4. 12:58
728x90
반응형

 

 

 

 

옵저버 패턴(Observer Pattern)이란?

 

 

옵저버 패턴(Observer Pattern)은 객체 간의 일대다 관계를 정의하여, 하나의 객체(주체, Subject)의 상태가 변경될 때, 이 상태를 관찰하는 여러 객체(옵저버, Observer)들에게 자동으로 알림을 보내는 디자인 패턴이다.

 

 

  • Observer Pattern은 크게 Subject(주체) 파트와 Observer(관찰자) 파트로 구성된다,
  • Subject(주체): 상태를 관리하며, 상태 변화 시 옵저버들에게 알림을 보내는 역할을 수행한다.
  • Observer(옵저버): 주체의 상태 변화를 관찰하며, 변경 사항을 수신하는 역할을 수행한다.
  • 객체 간의 느슨한 결합을 유지하면서도 효율적으로 상태 변화를 처리할 수 있는 디자인 패턴이다.
  • 유니티 엔진의 UnityEventAction 메서드는 이러한 옵저버 패턴의 개념을 간단하게 활용할 수 있도록 만든 도구다.

 

순서로 따져보자면

 

 

1. Subject(주체)의 상태가 변경된다.(이벤트 발생)

 

2. Subject(주체)는 자신의 상태가 변경되면 즉시 Observer(관찰자)에게 통지한다.

 

3. Observer(관찰자) Subject(주체)의 상태 변경을 감지하고 이에 대응한다.

 

 

의 순서로 옵저버 패턴은 이루어진다.

 

 

 

옵저버 패턴의 장점

 

  • 느슨한 결합: 주체와 옵저버는 서로에 대해 정보를 몰라도 상호작용할 수 있어 객체 간의 결합도가 낮다.
  • 확장성: 새로운 옵저버를 쉽게 추가할 수 있으며, 주체의 동작을 변경하지 않고도 여러 옵저버가 같은 주체를 관찰할 수 있습니다.

 

옵저버 패턴의 단점

 

  • 성능 문제: 옵저버의 수가 많아지면 주체가 상태 변화를 알릴 때 성능에 영향을 미칠 수 있다.
  • 의존성 문제: 옵저버가 주체의 상태 변화에 지나치게 의존하게 될 경우 시스템이 복잡해질 수 있다.

 

 

 

 

 

옵저버 패턴을 활용한 코드 예시

 

아래 코드는 옵저버 패턴을 활용해 날씨 알림 디스플레이를 만든 것으로 주체(WeatherStation)는 날씨(온도) 정보를 관리하고, 옵저버(WeatherDisplay)는 주체의 상태 변화를 감지해 이를 화면에 표시하는 역할을 하도록 만든 것이다.

 

 

 

Weather Station Class

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace JYJ_DesignPattern.Observer
{
    internal class WeatherStation
    {
        // 옵저버들을 저장할 리스트를 선언한다.
        private List<IWeatherObserver> observers = new List<IWeatherObserver>();

        // 온도 값을 저장하는 변수
        private float temperature;

        // 옵저버를 등록하는 메서드
        // 새로운 옵저버를 리스트에 추가한다.
        public void Subscribe(IWeatherObserver observer)
        {
            observers.Add(observer);
        }

        // 옵저버를 해제하는 메서드
        // 기존 옵저버를 리스트에서 제거한다.
        public void Unsubscribe(IWeatherObserver observer)
        {
            observers.Remove(observer);
        }

        // 주체의 상태(온도)를 변경하는 메서드
        // 온도를 업데이트하고, 옵저버들에게 알림을 보낸다.
        public void SetTemperature(float temp)
        {
            // 전달받은 온도를 저장한다.
            temperature = temp;

            // 옵저버들에게 알림을 보낸다.
            NotifyObservers();
        }

        // 옵저버들에게 상태 변경(온도 변화)을 알리는 메서드
        private void NotifyObservers()
        {
            // for문을 통해 등록된 모든 옵저버들에게 알림을 전달한다.
            for (int i = 0; i < observers.Count; i++)
            {
                // 각 옵저버의 Update 메서드를 호출하여 온도 변화를 알린다.
                observers[i].Update(temperature);
            }
        }
    }


    // IWeatherObserver 인터페이스는 옵저버들이 구현해야 하는 메서드를 정의한다.
    public interface IWeatherObserver
    {
        // 주체에서 상태 변화가 있을 때 호출되는 메서드
        // 온도 값을 전달받는다.
        void Update(float temperature);
    }

    // WeatherDisplay 클래스는 옵저버 역할을 한다.
    // 주체의 상태 변화에 따라 화면에 변화를 표시하는 기능을 구현한다.
    public class WeatherDisplay : IWeatherObserver
    {
        // 디스플레이 ID를 저장하는 변수 (각 디스플레이를 구분하기 위한 값)
        private string displayId;

        // 생성자: 디스플레이의 ID를 설정한다.
        public WeatherDisplay(string id)
        {
            displayId = id;
        }

        // 주체로부터 온도 변화 알림을 받을 때 호출되는 메서드
        // 온도 값을 받아 콘솔에 출력한다.
        public void Update(float temperature)
        {
            // 콘솔에 디스플레이 ID와 현재 온도를 출력한다.
            Console.WriteLine($"{displayId} 디스플레이 - 현재 온도: {temperature}도");
        }
    }
}

 

 

Main

static void Main(string[] args)
{
    // 날씨 정보 제공 주체 생성
    WeatherStation weatherStation = new WeatherStation();

    // 두 개의 디스플레이(옵저버) 생성
    WeatherDisplay display1 = new WeatherDisplay("디스플레이 1");
    WeatherDisplay display2 = new WeatherDisplay("디스플레이 2");
    WeatherDisplay display3 = new WeatherDisplay("디스플레이 3");

 
    // 디스플레이를 옵저버로 등록
    weatherStation.Subscribe(display1);
    weatherStation.Subscribe(display2);
    weatherStation.Subscribe(display3);

    Console.WriteLine("옵저버 등록 완료");

    // 날씨 정보 업데이트 (온도 변경)

    Console.WriteLine("1번 지역 날씨");
    weatherStation.SetTemperature(34.0f);
    Console.WriteLine("2번 지역 날씨");
    weatherStation.SetTemperature(22.5f);


    // 디스플레이 해제
    weatherStation.Unsubscribe(display1);
    weatherStation.Unsubscribe(display3);

    Console.WriteLine("디스플레이 1, 3 해제");

    // 다시 온도 업데이트
    Console.WriteLine("3번 지역 날씨");
    weatherStation.SetTemperature(30.0f);

}



 

 

  • WeatherStation 클래스
    • 옵저버(관찰자)를 관리하고 날씨(온도)를 변경하는 주체 역할을 수행한다.
    • 옵저버들을 등록(Subscribe)하고, 해제(Unsubscribe)하며, 날씨가 변경될 때마다 모든 옵저버에게 알림을 보낸다.(NotifyObservers).
  • IWeatherObserver 인터페이스:
    • 옵저버가 구현해야 하는 메서드를 정의하고 옵저버는 주체의 상태 변화(온도 변화)에 대한 알림을 받을 수 있게 한다.
  • WeatherDisplay 클래스:
    • IWeatherObserver 인터페이스를 구현한 옵저버 역할을 수행한다.

 

 

 

 

 

 

 

 

 

 

 

사진 출처 : https://refactoring.guru/design-patterns/observer

728x90
반응형