본문 바로가기
컴퓨터 과학/디자인패턴

[디자인패턴] 행위 패턴(7) : 옵저버(Observer)

by webcodur 2024. 3. 25.
728x90
반응형

목차

     

     

    옵저버(Observer)

    옵저버 디자인 패턴은 객체의 상태 변화를 관찰하는 관찰자들(Observer)에게 변화를 알리기 위해 사용하는 디자인 패턴이다. 어원적으로, '옵저버(Observer)'는 '관찰자'를 뜻하는 영단어로, 이 패턴에서는 한 객체의 상태 변화를 관찰하고, 그 변화에 반응하는 객체들을 의미한다.

    이 패턴의 주요 구성 요소는 다음과 같다:

    • Subject: 상태 변화가 발생하는 객체. Observer들을 자신의 리스트에 등록하고, 상태 변화가 있을 때 등록된 Observer들에게 알린다.
    • Observer: Subject의 상태 변화를 관찰하고, 변화가 있을 때 업데이트 받아야 하는 객체들. Subject의 상태 변화에 따라 동작하는 메소드를 구현한다.

     

    패턴 미적용 예시

    패턴을 적용하지 않은 상황에서는 게임 내의 여러 UI 컴포넌트(예: 점수 표시, 생명력 표시 등)가 플레이어의 상태를 각자 독립적으로 확인해야 한다. 이 경우, 플레이어의 상태가 바뀔 때마다 각 UI 컴포넌트를 개별적으로 업데이트 해야 하는 번거로움이 있다.

    class Player
    {
        public int Health { get; set; } = 100;
        // 플레이어의 다른 속성들...
    }
    
    class HealthBar
    {
        public void Update(Player player)
        {
            Console.WriteLine($"HealthBar Updated: {player.Health}");
        }
    }
    
    class ScoreDisplay
    {
        public void Update(Player player)
        {
            // 여기서는 예시를 단순화하기 위해 점수를 직접 Player에 넣지 않았음
            Console.WriteLine($"Score Updated: {/* 플레이어의 점수 */}");
        }
    }
    
    // 사용 예
    var player = new Player();
    var healthBar = new HealthBar();
    var scoreDisplay = new ScoreDisplay();
    
    // 플레이어의 상태가 변경될 때마다 수동으로 업데이트 호출
    player.Health -= 10;
    healthBar.Update(player);
    scoreDisplay.Update(player);
    

    이 코드에서 문제점은 플레이어의 상태가 바뀔 때마다 HealthBarScoreDisplay를 수동으로 업데이트 해야 한다는 것이다. 또한, 새로운 UI 컴포넌트가 추가될 때마다 그 컴포넌트도 수동으로 업데이트해야 하는 부담이 생긴다.

     

     

    패턴 적용 예시

    옵저버 패턴을 적용한 경우, 게임에서 플레이어의 상태(예: 생명력) 변화를 관찰하는 UI 컴포넌트들이 플레이어의 상태 변화를 자동으로 받아 업데이트할 수 있다. 이를 통해 코드의 결합도를 낮추고, 유지보수성을 향상시킬 수 있다. 아래는 C#을 사용한 옵저버 패턴의 구현 예시이다.

    // Observer 인터페이스 정의
    interface IObserver
    {
        void Update();
    }
    
    // Subject 인터페이스 정의
    interface ISubject
    {
        void Attach(IObserver observer);
        void Detach(IObserver observer);
        void Notify();
    }
    
    // Player 클래스가 Subject 역할을 한다
    class Player : ISubject
    {
        private List<IObserver> observers = new List<IObserver>();
        private int health = 100;
    
        // Health 속성 변경 시 모든 Observer에게 알림
        public int Health
        {
            get => health;
            set
            {
                health = value;
                Notify();
            }
        }
    
        // Observer를 추가한다
        public void Attach(IObserver observer)
        {
            observers.Add(observer);
        }
    
        // Observer를 제거한다
        public void Detach(IObserver observer)
        {
            observers.Remove(observer);
        }
    
        // 모든 Observer에게 상태 변경을 알린다
        public void Notify()
        {
            foreach (var observer in observers)
            {
                observer.Update();
            }
        }
    }
    
    // HealthBar는 Observer의 구현체이다.
    class HealthBar : IObserver
    {
        private Player player;
    
        public HealthBar(Player player)
        {
            this.player = player;
        }
    
        public void Update()
        {
            Console.WriteLine($"HealthBar Updated: {player.Health}");
        }
    }
    
    // ScoreDisplay는 Observer의 또 다른 구현체이다.
    // 예제를 단순화하기 위해 실제로 점수를 관리하는 로직은 생략함
    class ScoreDisplay : IObserver
    {
        public void Update()
        {
            Console.WriteLine("Score Updated: /* 플레이어의 점수 */");
        }
    }
    
    // 사용 예
    class Program
    {
        static void Main(string[] args)
        {
            var player = new Player();
            var healthBar = new HealthBar(player);
            var scoreDisplay = new ScoreDisplay();
    
            // Observer들을 Player에 등록한다
            player.Attach(healthBar);
            player.Attach(scoreDisplay);
    
            // 플레이어의 Health가 변경될 때마다, 등록된 Observer들이 자동으로 업데이트된다
            player.Health -= 10; 
            // 이 라인 실행 시, HealthBar와 ScoreDisplay가 자동으로 업데이트됨
        }
    }
    

     

    이 예시에서 Player 클래스는 ISubject 인터페이스를 구현하며, 게임 내의 주요 상태(예: 건강 상태)를 관리한다. HealthBarScoreDisplay클래스는 IObserver 인터페이스를 구현하여 플레이어의 상태 변화를 감지하고 이에 대응한다. 플레이어의 건강 상태가 변할 때마다 Player클래스는 모든 등록된 관찰자(Observer)들에게 변경 사항을 알리며(Notify 메서드), 각 관찰자는 자신의 Update 메서드를 통해 필요한 UI 업데이트를 수행한다.

     

    이 방식으로, 게임 개발자는 게임의 다양한 UI 요소들이 플레이어의 상태 변화에 따라 독립적으로, 그리고 자동적으로 업데이트되도록 할 수 있으며, 새로운 UI 요소를 추가하는 것도 훨씬 쉬워진다. 이는 코드의 재사용성과 확장성을 크게 향상시킨다.

    반응형