티스토리 뷰

Unity/Study

[Unity] 옵저버 패턴

Kim2558 2018. 7. 4. 23:12

출처 : https://www.youtube.com/watch?v=qwQ16sS8FSs


1. 옵저버 패턴


옵저버 패턴은 특정 객체(Subject)의 상태 변화에 따라 특정 객체와 연결된 다른 객체들(Observer)이 영향을 받는 1 : N 관계이다. 

옵저버 패턴은 Observer, Subject 두 종류로 나뉘는데 Observer는 Subject의 상태 변화를 관찰하는 객체이며 Subject는 Observer에게 상태 변화를 알리는 객체이다.

옵저버 패턴을 사용하는 이유로는 결합도를 낮추고 응집도를 높여 객체지향적인 프로그래밍을 하기 위해서이다. 특정 객체(Subject)의 상태 변화에 따라 영향을 받는 다른 객체들(Observer)이 무수히 많다면 특정 객체에는 다른 객체들의 정보가 무수히 필요하게되며 심각한 경우에는 이 정보들이 옳바르지 못한 곳에 끼어들 수도 있다. 이는 결과적으로 결합도를 높이고 응집도를 낮추게된다. C#에서는 delegate, event를 통해 옵저버 패턴을 구현하여 이를 방지한다.


2. 구현 방법


예로 사용될 코드는 플레이어가 마우스 좌 클릭을 했을 때 모든 적들의 색을 빨간색으로 바꾸는 코드이다. 제일 간단하고 좋은 구현 방법은 적들의 정보를 모두 배열로 받아 캐싱해놓고 마우스 좌 클릭을 했을 때 적들을 모두 빨간색으로 만드는 것 이다. 단순히 색을 바꾸는 기능 하나만을 한다면 좋은 방법이라고 생각한다. 하지만 옵저버 패턴을 공부하고 있으니 가정을 하나 한다. 플레이어가 마우스 우 클릭을 했을 때 적들을 빨간색으로 만드는 것 뿐만 아니라 적들은 각각 다른 행동을 취해야 하고 그 행동들이 수십가지가 있다고 가정했을 때 옵저버 패턴을 사용하지 않았을 경우 하나의 클래스 안에 적들의 모든 정보를 받고 적들의 모든 행동을 제어하는 코드가 들어가게 된다. 이는 바람직하지 못하다. 반면 옵저버 패턴을 사용했을 경우에는 모든 적들의 색을 빨간색으로 바꾸기만 할 때와 모든 적들의 다양한 행동을 제어할 때의 차이가 없어진다. 



Player (Subject)


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
31
32
33
34
35
36
37
38
39
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class Player : MonoBehaviour
{
 
    #region Singleton
    private static Player _instance;
    public static Player Instance
    {
        get
        {
            if(_instance == null)
            {
                _instance = FindObjectOfType(typeof(Player)) as Player;
            }
            return _instance;
        }
    }
    #endregion
 
 
    public delegate void ChangeEnemyColor(Color color);
    public event ChangeEnemyColor onEnemyHit;
 
    
    void Update () {
        if(Input.GetKeyDown(KeyCode.Space))
        {
            if(onEnemyHit != null)
            {
                onEnemyHit(Color.red);
            }
        }
    }
 
}
 
cs


#Region 안에 구현된 것은 Singleton 패턴이다. 옵저버 패턴에서 Subject는 하나이고 Observer들이 쉽게 접근 가능해야 하기 때문에 하나 또는 0개의 인스턴스만을 갖는 싱글톤 패턴으로 Subject를 작성했다. 그 밑에 delegate와 event 가 있는데 이것이 C#에서의 옵저버 패턴의 핵심이다. 여기서 event 는 멤버 변수가 delegate인 property라고 생각하면 쉽다. 

event에 Observer 객체들의 행동이 등록이 되면 마우스 좌 클릭이 이루어질 때 Observer들의 행동들이 실행이된다. 그렇기 때문에 아무리 Observer들이 늘어나거나 줄어들어도 Subject의 변경은 거의 필요하지 않다.


Enemy


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class Enemy : MonoBehaviour {
 
    // Use this for initialization
    void Start ()
    {
        Player.Instance.onEnemyHit += Damage;
    }
    
    public void Damage(Color color)
    {
        GetComponent<Renderer>().material.color = Color.red;
    }
 
    private void OnDisable()
    {
        if (Player.Instance != null)
            Player.Instance.onEnemyHit -= Damage;
    }
}
 
cs


Subject에 마우스 우 클릭이라는 상태 변화가 일어났을 경우 자신에게 알려달라고 event를 등록한다. 

그리고 자신이 Disable 됐을 경우 Subject에게 더 이상 자신에게 알려주지 말라고 event 등록을 해제한다. 



옵저버 패턴에도 단점이 있다고 한다. Subject의 코드를 봤을 때 무슨 동작을 하고 있는지 알 수 없기 때문이다. 각각의 Observer 들을 보아도 단편적인 것만 알 수 있지 전체적인 틀을 알수 없기는 마찬가지이다. 하지만 나는 그만큼 결합도가 낮아진 것이라고 생각하기 때문에 큰 단점이 된다고 생각하지는 않는다.





댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/01   »
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 31
글 보관함