핵심 인사이트 (3줄 요약)

  1. 본질: 플라이웨이트 (Flyweight) 패턴은 반복 객체의 공통 데이터를 공유 객체로 묶고, 변하는 값만 외부에서 주입해 메모리 사용을 줄이는 구조 패턴이다.
  2. 가치: 글자 렌더링, 게임 유닛, 지도 마커처럼 비슷한 객체가 수천·수만 개 생기는 상황에서 힙 메모리와 객체 생성 비용을 크게 낮출 수 있다.
  3. 판단 포인트: 내부 상태와 외부 상태를 명확히 분리할 수 있을 때만 효과적이며, 상태가 자주 변하거나 객체 정체성이 중요한 경우에는 오히려 구조가 복잡해질 수 있다.

Ⅰ. 개요 및 필요성

플라이웨이트 패턴은 많은 수의 유사 객체를 효율적으로 다루기 위해 공통 상태를 공유하는 설계 기법이다. 워드프로세서에서 같은 글꼴의 글자가 수천 번 반복되거나, 게임 화면에 동일한 적 유닛이 대량으로 등장하면 각 객체가 모양, 폰트, 텍스처 같은 데이터를 모두 개별 보유하는 순간 메모리 사용량이 급증한다. 이때 객체 수만큼 중복 저장되는 정보를 하나로 묶어 재사용하는 것이 플라이웨이트의 출발점이다.

이 패턴이 필요한 이유는 단순 메모리 절약에 그치지 않는다. 객체가 과도하게 늘어나면 가비지 컬렉션 (Garbage Collection, GC) 부담, 생성자 호출 비용, 캐시 비효율까지 함께 늘어난다. 즉 문제의 본질은 "객체 수"가 아니라 중복된 상태를 가진 객체 폭증이다.

플라이웨이트는 이 문제를 내부 상태 (Intrinsic State)와 외부 상태 (Extrinsic State) 분리로 해결한다. 공유 가능한 불변 정보는 객체 안에 두고, 호출 시마다 달라지는 좌표·크기·색상 같은 정보는 바깥에서 넘겨주면 같은 객체를 여러 맥락에서 재사용할 수 있다.

  • 📢 섹션 요약 비유: 같은 도장을 여러 장 찍을 때 도장 자체는 하나만 두고, 찍는 종이 위치만 바꾸는 것이 플라이웨이트의 생각이다.

Ⅱ. 아키텍처 및 핵심 원리

플라이웨이트 구조는 보통 클라이언트, 플라이웨이트 인터페이스, 구체 플라이웨이트, 그리고 공유 객체를 관리하는 팩토리로 이루어진다. 핵심은 객체가 스스로 모든 상태를 들고 있지 않는다는 점이다. 객체 내부에는 공유 가능한 핵심 정보만 남고, 실제 실행 맥락은 클라이언트가 메서드 호출 시 넘긴다.

아래 그림은 여러 클라이언트가 같은 공유 객체를 사용하되, 위치와 크기 같은 값은 외부에서 따로 전달하는 흐름을 보여준다.

┌──────────────────────────────────────────────────────────────────────┐
│ Shared object holds only reusable state                             │
├──────────────────────────────────────────────────────────────────────┤
│ Client A: pos(10,20), size=12 ─┐                                    │
│ Client B: pos(10,40), size=12 ─┼─▶ Flyweight Factory ─▶ Glyph "A"  │
│ Client C: pos(10,60), size=18 ─┘                       │            │
│                                                         ├─ intrinsic │
│                                                         │  font, path│
│                                                         │  bitmap    │
│                                                         └─ extrinsic │
│                                                            x, y, size│
│                                                            from call │
└──────────────────────────────────────────────────────────────────────┘
구성 요소역할설계 포인트
Flyweight공유 객체 인터페이스외부 상태를 파라미터로 받도록 설계
Concrete Flyweight실제 공유 데이터 보관불변성 유지가 중요
Flyweight Factory공유 객체 조회·생성키 관리와 캐시 전략 필요
Client외부 상태 보유호출 시 필요한 문맥 전달

설계에서 가장 중요한 질문은 "무엇을 공유할 것인가"다. 폰트 종류, 벡터 윤곽선, 공통 텍스처처럼 바뀌지 않는 값은 내부 상태로 적합하다. 반대로 좌표, 회전, 현재 체력처럼 인스턴스별로 바뀌는 값은 외부 상태로 분리해야 한다. 이 경계가 흐리면 공유 객체가 오염되어 버그가 생긴다.

또한 플라이웨이트는 캐싱과 다르면서도 연결된다. 캐싱은 계산 결과나 조회 결과를 저장하는 개념이고, 플라이웨이트는 객체 구조 자체를 공유하는 패턴이다. 하지만 실무 구현에서는 팩토리가 사실상 키 기반 캐시처럼 동작하므로 두 개념이 함께 나타난다.

  • 📢 섹션 요약 비유: 여러 사람이 같은 악보를 보되, 각자 앉은 자리와 연주 타이밍만 다르게 가져가는 오케스트라와 비슷하다.

Ⅲ. 비교 및 연결

플라이웨이트는 종종 싱글턴 (Singleton), 프로토타입 (Prototype), 오브젝트 풀 (Object Pool)과 혼동된다. 하지만 이 패턴들의 목적은 분명히 다르다. 싱글턴은 객체를 하나만 보장하고, 프로토타입은 복제로 생성을 줄이며, 오브젝트 풀은 생성 비용이 큰 객체를 재사용한다. 플라이웨이트는 "객체 수를 제한"하는 것이 아니라 객체가 가진 공통 상태를 공유한다는 점이 핵심이다.

비교 대상플라이웨이트싱글턴프로토타입오브젝트 풀
핵심 목적공통 상태 공유단일 인스턴스 보장복제 기반 생성비싼 객체 재사용
객체 수여러 개 가능1개필요 수만큼 복제제한된 풀 크기
상태 전략내부/외부 상태 분리전역 상태 보유 가능복제 후 수정반환 후 재할당
대표 예글자, 아이콘, 유닛설정 관리자템플릿 객체DB 연결, 스레드

연결 관점에서도 의미가 있다. 자바 문자열 풀 (String Pool)은 동일 문자열 리터럴을 공유한다는 점에서 플라이웨이트적 사고와 닮아 있고, 렌더링 엔진이나 지도 엔진의 심볼 관리도 같은 맥락이다. 즉 이 패턴은 GoF (Gang of Four) 구조 패턴이면서, 실제로는 메모리 아키텍처와 성능 최적화 문제에 직접 연결된다.

중요한 경계는 "공유가 항상 좋은가"가 아니라 "공유할수록 이득이 큰가"다. 외부 상태 전달 비용이 너무 크거나, 동시성 제어가 복잡해지면 오히려 일반 객체가 더 단순하고 안전할 수 있다.

  • 📢 섹션 요약 비유: 한 명당 우산을 전부 사 주는 것과, 같은 모양 우산을 창고에 두고 필요할 때 꺼내 쓰는 것의 차이가 플라이웨이트 비교의 핵심이다.

Ⅳ. 실무 적용 및 기술사 판단

실무에서 플라이웨이트를 채택해야 하는 대표 상황은 동일한 속성을 지닌 객체가 대량 발생하고, 그중 상당 부분이 불변 데이터일 때다. 예를 들어 워드프로세서의 글리프 (Glyph), 게임의 배경 타일, 지도 서비스의 공통 아이콘, 임베디드 장비의 정적 UI 자원은 플라이웨이트 적용 효과가 크다. 반대로 각 객체가 개별 생명주기와 복잡한 변경 상태를 갖는 도메인 객체라면 적용 이득이 줄어든다.

채택 판단 체크리스트

  1. 동일 속성을 가진 객체가 반복적으로 매우 많이 생성되는가?
  2. 공유 가능한 내부 상태의 크기가 충분히 큰가?
  3. 외부 상태를 호출 시 안전하게 주입할 수 있는가?
  4. 객체 정체성보다 메모리 효율이 더 중요한가?
  5. 팩토리 캐시의 키 충돌과 동시성 제어를 감당할 수 있는가?

대표 안티패턴

  • 가변 상태를 공유 객체 내부에 넣어 객체 간 오염이 발생하는 설계
  • 공유 이득이 거의 없는데도 패턴을 과잉 도입해 가독성만 떨어뜨리는 경우
  • 팩토리 캐시를 무제한 확장해 메모리 누수처럼 사용하는 경우

기술사 관점에서는 "메모리 절감"만 쓰면 부족하다. 상태 분리 가능성, 팩토리 관리 비용, 디버깅 난이도까지 함께 말해야 실제 설계 판단으로 인정받는다.

  • 📢 섹션 요약 비유: 플라이웨이트는 공용 자전거 시스템과 같아서, 자전거를 공유할 조건과 반납 규칙이 명확할 때만 도시 전체 효율이 올라간다.

Ⅴ. 기대효과 및 결론

플라이웨이트 패턴을 올바르게 적용하면 메모리 사용량 감소, 객체 생성 횟수 감소, 캐시 친화성 향상이라는 직접 효과를 얻는다. 이는 대량 렌더링이나 저사양 장치에서 특히 큰 차이를 만든다. 같은 데이터를 여러 번 중복 보관하지 않으므로, 시스템 규모가 커질수록 절감 폭도 함께 커진다.

하지만 전제조건도 분명하다. 공유 대상이 불변에 가깝고, 외부 상태를 다루는 코드가 명확해야 하며, 팩토리 관리 비용이 절감 이득보다 작아야 한다. 결국 플라이웨이트는 "객체를 적게 만든다"가 아니라 중복 상태를 공유 가능한 구조로 재설계한다는 관점으로 기억해야 한다.

앞으로도 그래픽스, 문서 처리, IoT (Internet of Things), 엣지 UI처럼 자원이 제한된 환경에서는 계속 유효한 패턴이다. 다만 비즈니스 도메인 객체에 무차별 적용하는 패턴이 아니라, 반복성과 불변성이 높은 데이터 집합에 선택적으로 쓰는 것이 정답이다.

  • 📢 섹션 요약 비유: 같은 벽돌로 여러 집을 짓되, 벽돌은 공장에서 공용으로 만들고 집의 모양만 현장에서 다르게 조립하는 생각이 플라이웨이트다.

관련 개념 맵

개념연결 포인트
Intrinsic State공유 객체 내부에 저장되는 불변 공통 정보
Extrinsic State호출 시 외부에서 주입되는 가변 문맥 정보
Flyweight Factory공유 객체를 키 기반으로 관리하는 진입점
Object Pool재사용이라는 점은 비슷하지만 목적은 생성 비용 절감에 더 가까움
String Pool동일 데이터를 공유한다는 점에서 대표적 유사 사례
Rendering Engine플라이웨이트가 자주 적용되는 실무 영역

관련 키워드 및 발전 흐름도

Repeated Objects Explosion
         │
         ▼
Intrinsic / Extrinsic State Split
         │
         ▼
Flyweight Factory + Shared Cache
         │
         ├──▶ String Pool
         ├──▶ Rendering Symbol Reuse
         └──▶ Game Tile / Glyph Sharing
         │
         ▼
Memory Footprint Reduction + Scalable Rendering

이 흐름은 "객체 폭증 문제 인식 → 상태 분리 → 공유 관리 → 대량 렌더링 최적화"로 이어지는 적용 맥락을 보여준다.

어린이를 위한 3줄 비유 설명

  1. 같은 나무 그림을 천 번 그릴 때, 그림판을 천 개 만드는 대신 나무 도장 하나를 같이 쓰는 게 플라이웨이트예요.
  2. 어디에 찍을지, 얼마나 크게 찍을지만 그때그때 바꾸면 훨씬 덜 힘들어요.
  3. 그래서 많은 그림을 그려도 종이와 힘을 아낄 수 있어요.