minstudio

플라이웨이트 패턴 (Flyweight)

플라이웨이트 패턴(Flyweight Pattern)은 수많은 동일한(또는 매우 유사한) 객체들을 생성할 때, 객체 내부의 공통된 데이터를 공유함으로써 메모리 낭비를 극적으로 줄이는 구조 패턴입니다.

마인크래프트 같은 게임에서 수만 개의 '나무 블록'을 그릴 때, 텍스처 이미지나 색상 같은 '변하지 않는 속성(Intrinsic)'은 한 번만 메모리에 올린 뒤 모든 블록이 공유합니다. 그리고 좌표(X,Y,Z) 같은 '각각 다른 속성(Extrinsic)'만 외부에서 받아 처리하여 OutOfMemory(메모리 초과) 에러를 방지합니다.

🪶 Flyweight: 공통 데이터 공유를 통한 메모리 절약 Flyweight Factory (캐시 저장소) 공유 객체: "Oak Tree" 텍스처: 5MB (단 1번만 로드) 참조(Reference) 공유 Tree 1 좌표: X=10, Y=20 Tree 2 좌표: X=15, Y=50 Tree 10000 좌표: X=99, Y=10 10000그루의 나무를 렌더링해도 무거운 텍스처 메모리는 단 1개분만 소모합니다!
<!-- ==========================================
// 📂 Flyweight (공유되는 속성)
// ==========================================

import java.util.HashMap;
import java.util.Map;

// 변하지 않는 공통 속성(Intrinsic State)을 담는 클래스
class TreeType {
    private String name;
    private String color;
    private String texture; // 무거운 데이터라 가정

    public TreeType(String name, String color, String texture) {
        this.name = name;
        this.color = color;
        this.texture = texture;
    }

    // 좌표(Extrinsic State)는 외부에서 인자로 받아와서 처리합니다.
    public void draw(int x, int y) {
        System.out.println(name + " 나무 렌더링 (텍스처:" + texture + ") at 좌표 (" + x + "," + y + ")");
    }
}

// ==========================================
// 📂 Flyweight Factory (캐싱 공장)
// ==========================================
class TreeFactory {
    static Map<String, TreeType> treeTypes = new HashMap<>();

    public static TreeType getTreeType(String name, String color, String texture) {
        // 맵에 동일한 종류의 나무가 있는지 검사하고, 없으면 새로 만들어서 캐시에 저장합니다.
        TreeType result = treeTypes.get(name);
        if (result == null) {
            result = new TreeType(name, color, texture);
            treeTypes.put(name, result);
            System.out.println(">>> [" + name + "] 텍스처를 메모리에 신규 로드했습니다.");
        }
        return result; // 기존에 있으면 캐시된 인스턴스를 반환
    }
}

// ==========================================
// 📂 Context (공유되지 않는 외부 속성)
// ==========================================
class Tree {
    private int x, y; // 각 나무마다 달라야 하는 고유 위치
    private TreeType type; // 팩토리를 통해 공유받은 속성 참조

    public Tree(int x, int y, TreeType type) {
        this.x = x;
        this.y = y;
        this.type = type;
    }

    public void draw() {
        type.draw(x, y); // 공유 객체에 자기 좌표를 넘겨 그려달라고 요청
    }
}

// ==========================================
// 📂 Main.java (사용 예시)
// ==========================================
public class Main {
    public static void main(String[] args) {
        // "참나무"라는 타입은 처음에 단 한 번만 생성됩니다.
        TreeType oak = TreeFactory.getTreeType("참나무", "녹색", "oak.png");
        
        Tree tree1 = new Tree(10, 20, oak);
        Tree tree2 = new Tree(15, 50, oak);
        
        // 또다시 "참나무"를 요구하면 기존에 로드된 객체의 참조를 반환합니다.
        TreeType sameOak = TreeFactory.getTreeType("참나무", "녹색", "oak.png");
        Tree tree3 = new Tree(99, 10, sameOak);

        tree1.draw();
        tree2.draw();
        tree3.draw();
    }
}
플라이웨이트 패턴 (Flyweight) | Minstudio