Chapter 8. 경량 패턴(Flyweight Pattern)

Date:     Updated:

카테고리:

태그:

인프런에 있는 이재환님의 강의 게임 디자인 패턴 with Unity 를 듣고 정리한 필기입니다. 😀

Chapter 8. Flyweight Pattern

🔔 Flyweight Pattern

image

image

한개의 고유 상태를 다른 객체들에서 공유하게 만들어 메모리 사용량을 줄인다.

내용이 같은 객체가 이미 있으면 새로 객체를 또 만들지 않고 그 내용 같은 기존 객체를 공유한다.

  • 게임 내에서 같은 메시와 텍스처를 여러번 메모리에 올릴 필요가 없기 때문에
  • TreeModel 객체는 하나만 존재하며 각 나무 인스턴스들은 이 TreeModel 객체 하나를 공유하며 참조할 뿐이다.
  • Tree 클래스에서는 인스턴스별로 다른 상태값만 남겨둔다.
  • 플라이웨이트 패턴에서의 객체 데이터 종류
    1. 모든 객체의 데이터 값이 같은 부분들만 모아둔 데이터. 즉 공유할 수 있는 데이터.
    2. 나머지 데이터는 인스턴스별로 값이 다른 외부 상태에 해당.
  • 생성된 객체를 공유하는 것이라서 C++ 포인터 개념과도 같다.

구현

  • 인스턴스를 요청 받았을 때 이전에 같은걸 만들어 놓은게 있는지 확인해보고 있다면 그걸 리턴해야 공유 기능이 유지된다.
    • 이러려면 이런 코드를 인터페이스 밑으로 숨겨두어야 한다.
      • 팩토리 메서드 패턴
    • 이미 생성해놓은 객체를 찾을 수 이도록 Pool을 관리해야 한다.
      • 다음 포스트에서 배울 오브젝트 풀 패턴이 여기에 사용 됨.


🔔 예제 1

📜Unit.cs

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

public interface Unit {   // 인터페이스
  
    string getName();
}

public class Marine : Unit   
{
    string name;
    int hp;

    public Marine(string name)
    {
        this.name = name;
    }

    public string getName()   // 오버라이딩
    {
        return name;
    }
}


📜UnitFactory.cs

  • 생성된 Marine 객체들을 Dictionary 자료 구조에 보관하여 관리한다.
    • name 이 같은 Marine이면 새로 만들지 않고 그 name이 같은 기존 Marine 객체를 리턴해준다.
      • 내용 같으면 새로 만들지 않기 위하여. for 메모리 절약
    • 현재 생성된 Marine 객체들 중 같은 name 을 가진 객체가 없을 경우에만 생성하고 이를 Dictionary에 추가해준다.
    • 만약 name 같은 Marine 객체가 있다면 기존 그 객체를 리턴한다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UnitFactory : MonoBehaviour {

    static Dictionary<string, Marine> dic = new Dictionary<string, Marine>();  // 이미 생성해놓은 Marine 객체가 있는지 관리해야 해서

    public static Marine getPerson(string name)
    {
        if (!dic.ContainsKey(name))   // 해당 이름의 생성해 놓은 객체가 없을 때만 생성
        {
            Marine tmp = new Marine(name);
            dic.Add(name, tmp);  // Dictionary 에 추가
        }
        return dic[name];  // 만들어둔거 리턴
    }
}


📜FlyweightUse.cs

  • p3객체가 생성될 때 이름이 “홍길동”으로 같은 p1 객체가 이미 있기 때문에 새롭게 생성하지 않는다.
    • p3은 기존에 생성 되었던 p1객체를 리턴받게 되며
    • p1p3은 동일한 객체를 가리킨다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FlyweightUse : MonoBehaviour {

	void Start () {
        Marine p1 = UnitFactory.getPerson("홍길동");
        Marine p2 = UnitFactory.getPerson("전우치");
        Marine p3 = UnitFactory.getPerson("홍길동");

        Debug.Log(p1 == p2);  // 둘이 다르다.
        Debug.Log(p1 == p3);  // 둘이 동일하다.

        Debug.Log("name : " + p1.getName());
    }

}


🔔 예제 2

유니티 오브젝트에 적용하기

  • 유니티 오브젝트들은(정확히 말하면 오브젝트에 붙어있는 컴포넌트들) MonoBehaviour를 상속 받는다.
    • MonoBehaviour를 상속 받는 오브젝트들은 new를 통해 생성하면 안된다.

📜Unit.cs

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

public interface Unit {   // 인터페이스
  
    string getName();
    void setName(string name);
}


📜Marine.cs

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

public class Marine : MonoBehaviour, Unit
{
    public string name;
    public int hp;

    public void setName(string name)
    {
        this.name = name;
    }

    public string getName()
    {
        return name;
    }

    void Start()
    {

    }
}


📜UnitFactory.cs

  • 생성된 Marine 객체들을 Dictionary 자료 구조에 보관하여 관리한다.
    • name 이 같은 Marine이면 새로 만들지 않고 그 name이 같은 기존 Marine 객체를 리턴해준다.
      • 내용 같으면 새로 만들지 않기 위하여. for 메모리 절약
    • 현재 생성된 Marine 객체들 중 같은 name 을 가진 객체가 없을 경우에만 생성하고 이를 Dictionary에 추가해준다.
    • 만약 name 같은 Marine 객체가 있다면 기존 그 객체를 리턴한다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class UnitFactory : MonoBehaviour {

    Dictionary<string, GameObject> dic = new Dictionary<string, GameObject>();
    public GameObject marine;

    public GameObject getMarine(string name)
    {
        if (!dic.ContainsKey(name))
        {
            float x = (float)Random.Range(-10, 11);
            float z = (float)Random.Range(-10, 11);
            Vector3 pos = new Vector3(x, 1.0f, z);

            //Marine obj = new Marine(name);
            GameObject obj = Instantiate(marine, pos, Quaternion.identity);
            obj.GetComponent<Marine>().setName(name);
            dic.Add(name, obj);
        }
        return dic[name];
    }
}



📜FlyweightUse.cs

  • p3객체가 생성될 때 이름이 “홍길동”으로 같은 p1 객체가 이미 있기 때문에 새롭게 생성하지 않는다.
    • p3은 기존에 생성 되었던 p1객체를 리턴받게 되며
    • p1p3은 동일한 객체를 가리킨다.

아래 코드에서 오브젝트 데이터는 단 2개일뿐이며 대신 렌더링은 3개가 된다.

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

public class FlyweightUse : MonoBehaviour {

	void Start () {
        UnitFactory factory = GetComponent<UnitFactory>();

        for (int i=0; i< 10; i++)
        {
            factory.getMarine("홍길동" + i);
        }

        GameObject p1 = factory.getMarine("홍길동");
        GameObject p2 = factory.getMarine("전우치");
        GameObject p3 = factory.getMarine("홍길동");

        if (p1 == p3)
        {
            Debug.Log("name : " + p1.GetComponent<Marine>().getName());
        }
    }
}



🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우 
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄

맨 위로 이동하기

Design Pattern 카테고리 내 다른 글 보러가기

댓글 남기기