이 글은 해당 유튜브를 보고 진행한 것에 대해 공부한 것을 정리한 글입니다.
플라이웨이트 패턴 (Flyweight Pattern)
플라이웨이트 패턴은 공유 데이터를 중앙 집중화하여 게임의 중복 데이터를 줄이는 최적화 패턴입니다.
개별 오브젝트가 각자 데이터 복사본을 저장하는 대신 이 공유 데이터를 참조하도록 하는 것입니다.

특징
- 공통 데이터의 공유를 통해 메모리 최적화
- 플라이웨이트 패턴은 여러 객체 간에 공통 상태를 공유함으로써 메모리 사용을 줄이는 구조적 디자인 패턴입니다.
- 동일한 정보를 중복 저장하지 않고, 필요에 따라 참조해서 사용하는 방식으로 동작합니다.
- 성능에 초점을 둔 최적화 패턴
- 일반적인 디자인 패턴들이 구조나 유연성에 중점을 둔다면, 플라이웨이트는 명확히 성능과 메모리 절약에 목표를 둡니다.
- 수많은 객체가 생성될 때 메모리 낭비를 줄여 퍼포먼스를 확보할 수 있습니다.
- Unity GameObject와 메모리
- Unity에서 여러 개의 GameObject가 생성되면, 각 객체는 고유한 데이터 필드(위치, 상태 등)뿐 아니라 공통 구성 요소조차도 개별적으로 복사됩니다.
- 특히 구조체, 배열 같은 Value Type은 참조가 아닌 복사로 처리되므로, 메모리 사용량이 급격히 증가할 수 있습니다.
- 이 때 플라이웨이트 패턴을 적용하면 공통 구성 요소만 공유하고 개별 데이터는 분리함으로써, 메모리 효율을 극대화할 수 있습니다.
장점
- 대량의 오브젝트를 효과적으로 관리 가능
- 수천 개의 오브젝트가 공통 상태를 공유할 때 유용하게 사용 가능합니다.
- 수많은 오브젝트를 인스턴스화해야 하는 경우에 플라이웨이트를 사용하면 더 효과적으로 확장 가능합니다.
- 리소스가 제한된 플랫폼에 적합
- 모바일, VR 기기처럼 메모리 리소스가 제한적인 플랫폼에서 성능 최적화에 특히 유용합니다.
- 확장성과 유지보수성 향상
- 공통 상태를 별도로 관리하므로 변경이 필요한 경우 한 군데만 수정하면 전체에 적용됩니다.
단점
- 관리 복잡성 증가
- 객체 자체뿐만 아니라 공유 상태까지 별도로 관리해야 하므로 설계가 복잡해질 수 있습니다.
- 오버헤드 발생 가능
- 공유 데이터를 관리하는 컨트롤러나 팩토리 로직이 추가되므로, 오히려 성능을 떨어뜨릴 수도 있습니다.
- 그렇기 때문에 유닛의 숫자가 많아 추가되는 오버헤드보다 얻는 장점이 더 크다고 이야기할 수 있을 때만 플라이웨이트 패턴의 장점이 발휘됩니다.
- 유연성 저하
- 공통 데이터를 강제로 공유하게 되믐로, 개별 객체의 커스터마이징이 어려워질 수 있습니다.
- 이를 보완하려면 공유 데이터 + 개별 데이터의 조합 구조로 설계해야 합니다.
플라이웨이트 패턴 사용 예시
군중 시뮬레이션
배경에 군중이 있는 시뮬레이션 게임을 제작할 때, 혹은 수백 명의 NPC가 등장하는 게임을 제작할 때, 플라이웨이트 패턴을 사용하여 모델, 애니메이션, 텍스처를 공유하는 역동적인 대규모 군중을 만들 수 있습니다.
캐릭터/무기 스킨 및 커스터마이징
무기의 속성이나 캐릭터 스킨의 공통된 기본 프로퍼티는 플라이웨이트로 공유하고, 커스터마이징 데이터만 개별적으로 저장할 수 있습니다.
레벨 오브젝트 최적화
숲을 디자인한다면 나무의 모든 보편적인 프로퍼티를 Tree라는 기본 클래스에 저장합니다. 그러면 서브 클래스(PineTree, MapleTree 등)에서 해당 프로퍼티를 반복할 필요가 없습니다.
또는 숲이나 도시 같은 씬에서 수많은 나무, 바위, 가로등 등 반복되는 요소들의 공통 속성(모델, 콜라이더, 머터리얼 등)을 공유하고, 위치나 회전 같은 정보만 개별 저장합니다.
구현 예시 : 리팩터링 이전 코드
public class UnrefactoredUnitInstance : MonoBehaviour
{
public string factionName;
public Sprite factionIcon;
public int baseHealth;
public int baseAttack;
public int baseDefense;
public int baseMovement;
// 이 유닛 인스턴스의 고유 상태
public int health;
public int attack;
public int defense;
public int movement;
public Vector3 position;
private void Start()
{
RefreshUnitStats();
}
private void RefreshUnitStats()
{
health = baseHealth;
attack = baseAttack;
defense = baseDefense;
movement = baseMovement;
// . . . 세력 데이터에 따라 다른 유닛 컴포넌트 업데이트
}
public void SetFactionData(string factionName, Sprite factionIcon,
int baseHealth, int baseAttack, int baseDefense, int baseMovement)
{
this.factionName = factionName;
this.factionIcon = factionIcon;
this.baseHealth = baseHealth;
this.baseAttack = baseAttack;
this.baseDefense = baseDefense;
this.baseMovement = baseMovement;
RefreshUnitStats();
}
}
구현 예시 : 플라이웨이트 패턴 적용
// 플라이웨이트 오브젝트(스크립터블 오브젝트)
[CreateAssetMenu]
public class FactionData : ScriptableObject
{
public string factionName;
public Sprite factionIcon;
public int baseHealth;
public int baseAttack;
public int baseDefense;
public int baseMovement;
}
// 컨텍스트 오브젝트
public class UnitInstance : MonoBehaviour
{
public FactionData factionData;
private void Start()
{
RefreshUnitStats();
}
private void RefreshUnitStats()
{
health = factionData.baseHealth;
attack = factionData.baseAttack;
defense = factionData.baseDefense;
movement = factionData.baseMovement;
// . . .세력 데이터에 따라 다른 유닛 컴포넌트 업데이트
}
// 이 유닛 인스턴스의 고유 상태
public int health;
public int attack;
public int defense;
public int movement;
public Vector3 position;
// . . . 여기에 다른 고유 상태 추가
}
예시: 샘플 프로젝트
해당 샘플 프로젝트는 'Toggle Flyweight' 버튼을 누르면 씬에 배치된 많은 전투기의 머터리얼이 변경되면서 색이 바뀌게 됩니다.

ShipData : 공유 데이터를 담는 Flyweight 클래스
[CreateAssetMenu(fileName = “ShipData”, menuName = “Flyweight/ShipData”, order = 1)]
public class ShipData : ScriptableObject
{
public string UnitName;
public string Description;
public float Speed;
public int AttackPower;
public int Defense;
}
- ShipData는 Unity의 ScriptableObject를 상속받아 생성된 데이터 객체입니다.
- CreateAssetMenu 속성 덕분에 Unity Editor 상에서 우클릭 > Flyweight > ShipData 메뉴로 쉽게 생성 가능합니다.
- 이 클래스는 공유 가능한 값들만 담고 있습니다. (이름, 설명, 스탯 등)
- 즉, 이 클래스는 게임 내 모든 Ship들이 공통적으로 사용할 수 있는 데이터를 담는 Flyweight 객체입니다.
- 인스턴스 수백 개가 공유하더라도 메모리에는 단 한 번만 로드됩니다.
Ship : 고유 상태와 공유 상태를 함께 갖는 게임 오브젝트
공유할 수 있는 부분은 ShiptData로 분리하고, 개별 상태는 Ship 클래스가 자체 보유하고 있습니다.
public class Ship : MonoBehaviour
{
[SerializeField] private ShipData m_SharedData;
[SerializeField] private float m_Health;
public void Initialize(ShipData data, float health)
{
m_SharedData = data;
m_Health = health;
}
public void DisplayShipInfo()
{
Debug.Log($”Name: {sharedData.UnitName}, Health: {m_Health}”);
}
}
- Ship 클래스는 실제로 게임 씬에서 등장할 유닛 객체입니다.
- m_SharedData는 모든 Ship이 공유할 수 있는 공통 속성 데이터(ShipData)입니다.
- m_Health는 각 Ship 객체마다 고유하게 유지되는 데이터, 즉 개별 상태입니다.
- Initialize 메서드로 외부에서 공통 데이터와 초기 체력을 설정할 수 있습니다.
- DisplayShipInfo는 유닛 이름(공유 데이터)과 체력(고유 데이터)을 출력합니다.
ShipFactory : 플라이웨이트 적용된 Ship을 대량 생성하는 팩토리
public class ShipFactory : MonoBehaviour
{
[SerializeField] private Ship shipPrefab;
[SerializeField] private ShipData sharedShipData;
[SerializeField] private float spacing = 1.0f;
void Start()
{
GenerateShips(10, 10);
}
public void GenerateShips(int rows, int columns)
{
for (int i = 0; i < rows; i++)
{
for (int j = 0; j < columns; j++)
{
Vector3 position = new Vector3(i * spacing, 0, j *
spacing);
Ship newShip = Instantiate(shipPrefab, position,
Quaternion.identity, transform);
newShip.Initialize(sharedShipData, 100);
// 초기 체력은 100으로 가정
newShip.name = $”Ship_{i * columns + j}”;
}
}
}
}
- ShipFactory는 Ship 객체를 10x10 그리드로 총 100개를 생성합니다.
- shipPrefab은 프리팹 참조입니다. 실제로 생성할 Ship GameObject의 원본입니다.
- sharedShipData는 모든 Ship 인스턴스가 사용할 공통 ShipData 참조입니다.
- GenerateShips는 위치를 조금씩 다르게 하여 유닛을 배치하고, Initialize를 통해 같은 데이터를 공유하게 합니다.
- sharedShipData는 한 번만 생성된 후 모든 Ship이 참조합니다.
플라이웨이트 패턴이 적용됐을 때의 Memory Profiler를 통한 메모리 확인

프리팹 vs 플라이웨이트
프리팹 시스템은 플라이웨이트 패턴을 구현한 것으로 간주할 수 있지만 접근 방식과 범위에서 차이가 있습니다.
- 프리팹은 전체 구조 공유
- Unity의 프리팹은 GameObject의 전체 구성 요소 및 계층 구조를 재사용하는 데 초점을 둡니다.
- 다수의 동일한 객체를 손쉽게 인스턴스화할 수 있으며, 프리팹을 수정하면 모든 인스턴스에 반영됩니다.
- 플라이웨이트는 일부 속성만 선택적으로 공유
- 플라이웨이트는 특정 데이터 필드 또는 프로퍼티만 선택적으로 공유합니다.
- 전체 구조는 그대로 두고, 텍스처, 애니메이션, 수치 값 같은 공통 속성만 메모리 최적화를 위해 분리합니다.
- 플라이웨이트 패턴은 특정 게임 오브젝트 구조로 한정되지 않으므로 공유 데이터를 더 유연하게 분리하고 관리할 수 있습니다.
프리팹은 복잡한 게임 오브젝트를 재사용하는 데 적합하지만, 플라이웨이트 패턴을 사용하면 수많은 오브젝트가 프로퍼티의 일부만 공유하므로 더 최적화할 수 있습니다.
프리팹으로 전체 구조를 재사용하고, 내부의 반복적 속성을 플라이웨이트로 관리하면 확장성과 성능 모두 확보할 수 있습니다.
'Unity' 카테고리의 다른 글
| [Unity] 디자인 패턴 : Dirty Flag 패턴 (0) | 2025.06.18 |
|---|---|
| [Unity] 디자인 패턴 : Strategy 패턴 (0) | 2025.06.17 |
| [Unity] MVC, MVP, MVVM 패턴 (0) | 2025.06.17 |
| [Unity] 디자인 패턴 : Singleton 패턴 (0) | 2025.06.17 |
| [Unity] 디자인패턴 : Object Pool (1) | 2025.06.16 |