[C/C++] 플라이웨이트 패턴(Flyweight Pattern)

할랑말랑·2026년 3월 30일

C/C++

목록 보기
42/45

플라이웨이트 패턴(Flyweight Pattern)

공유를 통해 많은 수의 객체를 효율적으로 지원하는 디자인 패턴
같은 데이터는 한 번만 메모리에 저장
여러 객체가 공유해서 사용
메모리 절약이 목적

1. 핵심

  • 내재적 상태 (Intrinsic State) : 공유 가능한 데이터, 변하지 않는 데이터
  • 외재적 상태 (Extrinsic State) : 공유 불가능한 데이터, 객체마다 다른 데이터

2. 구성 요소

  • Flyweight : 공유할 데이터를 가지는 객체
  • Context : 플라이웨이트를 사용하는 객체
  • FlyweightFactory : 기존에 생성된 객체가 있는지 확인하고, 있으면 반환하며 없으면 새로 생성하여 캐싱(Caching)
  • Client (클라이언트) : 패턴을 사용하는 코드

3. 장점

  • 수많은 객체를 생성할 때 메모리 절감, 객체 생성 비용 감소

4. 단점

  • 코드 복잡도 증가
  • 상태 분리의 어려움

Flyweight Pattern 예시

Flyweight : Slime
Context : SType
FlyweightFactory : SlimeFactory

#include <iostream>
#include <map>      // std::map을 사용하기 위해 포함합니다.
#include <vector>   // std::vector를 사용하기 위해 포함합니다.
#include <string>   // std::string을 사용하기 위해 포함합니다.

// 플라이웨이트(Flyweight) 객체 클래스입니다.
// 여러 Slime 객체들이 공유할 데이터를 담고 있습니다. (본질적 상태, Intrinsic State)
class SType
{
private:
    std::string image; // 이미지 데이터
    std::string sound; // 사운드 데이터

public:
    // 생성자: 이미지와 사운드 데이터를 받아 초기화합니다.
    SType(const std::string& _image, const std::string& _sound) : image(_image), sound(_sound) {}

    // 이미지 정보를 출력하는 함수
    void imagePrint()
    {
        std::cout << image << std::endl;
    }
    // 사운드 정보를 출력하는 함수
    void SoundOutput()
    {
        std::cout << sound << std::endl;
    }
};

// 실제 게임에 등장할 Slime 객체 클래스입니다.
class Slime
{
private:
    int hp;     // 각 슬라임마다 다른 고유 데이터 (외재적 상태, Extrinsic State)
    int attack; // 각 슬라임마다 다른 고유 데이터 (외재적 상태, Extrinsic State)
    std::shared_ptr<SType> type; // 공유되는 데이터(SType)에 대한 포인터

public:
    // 생성자: 고유 데이터(hp, attack)와 공유 데이터(type)를 받아 초기화합니다.
    Slime(int _hp, int _attack, std::shared_ptr<SType> _type) : hp(_hp), attack(_attack), type(_type) {}

    // Slime의 모든 정보를 출력하는 함수
    void ShowInfo()
    {
        std::cout << "HP : " << hp << ", 공격력 : " << attack << std::endl;
        type->imagePrint();  // 공유 데이터의 이미지 출력 함수 호출
        type->SoundOutput(); // 공유 데이터의 사운드 출력 함수 호출
    }
};

// 플라이웨이트 객체(SType)를 생성하고 관리하는 팩토리 클래스입니다.
class SlimeFactory
{
private:
    // SType 객체들을 저장하는 맵. string(타입 이름)을 키로 사용합니다.
    std::map<std::string, std::shared_ptr<SType>> stype;

public:
    // SType 객체를 가져오는 함수. 없으면 새로 만들고, 있으면 기존 객체를 반환합니다.
    std::shared_ptr<SType> getSlimeType(std::string _name, std::string _color, std::string _sound)
    {
        // 맵에서 _name 키를 가진 SType이 있는지 확인합니다.
        if (stype.find(_name) == stype.end())
        {
            // 없으면 새로 생성하여 맵에 추가합니다.
            std::cout << "[생성] - " << _name << " 타입 생성" << std::endl;
            stype[_name] = std::make_shared<SType>(_color, _sound);
        }
        else
        {
            // 이미 존재하면 메시지를 출력하고 기존 객체를 재사용합니다.
            std::cout << "[재사용] - " << _name << " 타입 재사용" << std::endl;
        }
        // 해당 SType 객체를 반환합니다.
        return stype[_name];
    }
};

int main()
{
    SlimeFactory factory;
    std::vector<Slime> slimes; // 생성된 슬라임들을 담을 벡터

    // "파란슬라임" 타입을 팩토리로부터 가져옵니다.
    // 이 시점에 "파란슬라임" SType 객체가 처음으로 생성됩니다.
    auto bluetype = factory.getSlimeType("파란슬라임", "이미지 : 파랑색", "울음소리 : 꾸오오옥");

    // 100마리의 슬라임을 생성합니다.
    for (int i = 0; i < 100; i++)
    {
        // 모든 슬라임이 위에서 만든 bluetype 객체 하나를 공유하게 됩니다.
        // SType 객체는 1개만 존재하고, 100개의 Slime 객체는 각자 다른 hp와 attack만 가집니다.
        slimes.push_back(Slime(10 + i, 20 + i, bluetype));
    }

    // 생성된 슬라임들의 정보를 출력합니다.
    for (auto slime : slimes)
    {
        slime.ShowInfo();
    }

    return 0;
}

  • 100마리의 슬라임을 만들어도 SType 객체는 단 하나만 유지한다.

0개의 댓글