• Tistory
    • 태그
    • 위치로그
    • 방명록
    • 관리자
    • 글쓰기
Carousel 01

[디자인패턴] 관찰자 패턴 (Observer Pattern)

Programming/디자인패턴 2020. 7. 2. 19:46

◎ 정의

 

옵서버 패턴(observer pattern)은 객체의 상태 변화를 관찰하는 관찰자들, 즉 옵저버들의 목록을 객체에 등록하여 상태 변화가 있을 때마다 메서드 등을 통해 객체가 직접 목록의 각 옵저버에게 통지하도록 하는 디자인 패턴이다. 주로 분산 이벤트 핸들링 시스템을 구현하는 데 사용된다. 발행/구독 모델로 알려져 있기도 하다.

- 출처 : 위키백과

 

- 즉 관찰자 패턴은 여러 객체들 간에 일대다의 의존성을 갖고서 한 객체의 상태에 변경사항이 생기면 그 객체에 의존적인 다른 나머지 객체들이 변경사항을 통보받아서 지시한 동작이 알아서 실행되도록 할 때 사용된다.

 


 

◎ 활용

 

- 게임 내 업적 시스템이나 캐릭터의 상태를 나타내는 UI 등 정보를 받아야 하는 주체가 계속해서 해당 데이터를 확인하는 것이 아니라 특정 이벤트가 발생했을 때만 처리하면 되는 모든 부분에서 유용하게 쓰인다.

 


 

 

◎ 장점 / 단점

 

○ 장점

 

- 객체 간의 결합도가 느슨하면서 일관성 유지가 가능하다.

 

- 객체 간 서로 상호작용하므로 변경된 정보를 갱신하는데 용이하다.

 

 

○ 단점

 

- 등록한 관찰자를 삭제할 때 removeObserver()와 같은 일련의 처리를 하지 않으면 불필요한 퍼포먼스 낭비가 일어날 가능성이 있다.

 

- 각각의 관찰자에서 처리되는 작업이 모호한 경우가 생길 수 있다. 가령 동시에 A와 B라는 이벤트가 발생했을 때 A와 B가 서로의 상태에 따라 각기 다른 처리를 하도록 참조된 경우 해당 이벤트의 처리 순서에 따라 결과가 달라지는 상황이 생길 수 있다.

 

- 프로그램에서 코드가 서로 어떻게 상호작용하는지를 알기가 어렵기 때문에 런타임 때에 디버그를 걸어서 확인해야 하는 상황이 생길 수 있다.

 


 

◎ 구현 코드

 

○ 기본 구현

 

< Observer.cs >

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public interface IObserver
{
    void Notify();
    void AddObserver(Observer observer);
    void RemoveObserver(Observer observer);
}

public class Observer : MonoBehaviour
{
    public virtual void OnNotify() { }
}

- IObserver의 인터페이스를 상속받아 구현하면 이벤트의 주체(Subject) 역할을 하게 되며 Observer 클래스를 상속할 경우 관찰자의 역할을 하게 된다.

 

 

< Box.cs >

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Box : Observer /*관찰자등록*/
{
    public GameObject box_object;   // 대상 객체와 연결필요

    public Subject subject;         // 관찰자 주체 연결

    private void Start()
    {
        if (subject != null)
        {
            subject.AddObserver(this);
        }    
    }

    public override void OnNotify()
    {
        if (box_object != null)
        {
            RandomMove();
            Debug.Log("이벤트 수신!");
        }

        void RandomMove()
        {
            box_object.transform.position = new Vector3(Random.Range(0, 10f), Random.Range(0, 10f), Random.Range(0, 10f));
        }
    }
}

- Box 클래스는 자기 자신을 관찰자로 등록하고 이벤트가 수신되면 box_object의 위치를 랜덤 하게 이동시킨다.

 

 

< Subject.cs >

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Subject : MonoBehaviour, IObserver
{
    List<Observer> observer_list = new List<Observer>();    // 관찰자를 담는 리스트

    float time;

    private void Update()
    {
        time += Time.deltaTime;

        if (time > 3.0f)
        {
            Notify();
            time = 0;

            Debug.Log("이벤트 발신!");
        }
    }

    // 전체에 이벤트 전송
    public void Notify()
    {
        for(int i = 0; i < observer_list.Count; ++i)
        {
            observer_list[i].OnNotify();
        }
    }

    // 관찰자 추가
    public void AddObserver(Observer observer)
    {
        observer_list.Add(observer);
    }

    // 관찰자 제거
    public void RemoveObserver(Observer observer)
    {
        observer_list.Remove(observer);
    }
}

- 관찰자 주체로써 구현해야 할 함수를 정의하고 3초마다 모든 관찰자에게 메시지를 보낸다.

 

 

 

○ 유니티 엔진 C#의 Delegate 사용

 

- 관찰자 패턴의 기본적인 구현은 위와 같지만 유니티 엔진의  C#에서는 Delegate를 이용하면 같은 기능을 더욱 쉽게 구현이 가능하다.

 

< Subject.cs >

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Subject : MonoBehaviour
{
    public delegate void event_handler();
    public event_handler evnethandler;

    float time;

    private void Update()
    {
        time += Time.deltaTime;

        if (time > 3.0f)
        {
            time = 0;
            evnethandler();
            Debug.Log("이벤트 발신!");
        }
    }
}

- 이벤트를 담을 델리게이트를 선언한다.

 

< Box.cs >

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Box : MonoBehaviour
{
    public GameObject box_object;   // 대상 객체와 연결필요

    public Subject subject;         // 관찰자 주체 연결

    private void Start()
    {
        if (subject != null)
        {
            subject.evnethandler += new Subject.event_handler(OnNotify);
        }    
    }

    public void OnNotify()
    {
        if (box_object != null)
        {
            RandomMove();
            Debug.Log("이벤트 수신!");
        }

        void RandomMove()
        {
            box_object.transform.position = new Vector3(Random.Range(0, 10f), Random.Range(0, 10f), Random.Range(0, 10f));
        }
    }
}

- Subject에 있는 델리게이트에 원하는 동작을 추가한다.

저작자표시 비영리 변경금지 (새창열림)

'Programming > 디자인패턴' 카테고리의 다른 글

[디자인패턴] 경량 패턴, 플라이웨이트 패턴 (Flyweight Pattern)  (0) 2020.07.01
[디자인패턴] 명령 패턴, 커맨드 패턴 (Command Pattern)  (0) 2020.06.30
블로그 이미지

BlackTopaz

e-mail : vluebear@naver.com

,

카테고리

  • 분류 전체보기 (80)
    • Programming (3)
      • C# (0)
      • Unity (0)
      • 디자인패턴 (3)
    • 프로그래밍 문제 풀이 (75)
      • C# (49)
      • MySQL (26)
    • 개발 일지 (0)
      • Project_EDM (0)
    • 디버깅 & 오류 해결 로그 (2)
      • Unity (2)

태그목록

  • C#
  • 프로그래밍 문제 풀이
  • 유니티
  • 프로그래머스
  • mysql
  • 디자인패턴
  • Unity
  • 게임프로그래밍
  • 유니티 에러
  • Unity Error

글 보관함

달력

«   2026/02   »
일 월 화 수 목 금 토
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

링크

BlackTopaz

블로그 이미지

e-mail : vluebear@naver.com

LATEST FROM OUR BLOG

RSS 구독하기

LATEST COMMENTS

BLOG VISITORS

  • Total :
  • Today :
  • Yesterday :

Copyright © 2015 Socialdev. All Rights Reserved.

티스토리툴바