본문 바로가기
Study/Design Pattern

[Design Pattern] Flyweight Pattern (플라이웨이트 패턴)

by J_Kkikki 2026. 6. 7.

[구조 패턴] Flyweight 패턴

= '캐시' 를 패턴화 한 것!

객체를 가볍게 유지하여 '메모리 사용량을 줄이는' 데 집중함!

 

자주 변화하는 속성(extrinsit)과 변하지 않는 속성(intrinsit)을 분리

intrinsit(변하지 않는 속성): 캐시하여 재사용(메모리 사용 줄이다!). 그래서 수천, 수만 개의 객체를 효율적으로 관리 가능!

 

 

[패턴 구조]

- Flyweight : 경량 객체를 묶는 인터페이스

- ConcreteFlyweight : 공유 가능, 재사용되는 객체(intrinsic)

- UnsharedConcreteFlyweight : 공유 불가능한 객체(extrinsic)

- FlyweightFactory : 경량 객체를 만드는 공장 역할과 캐시 역할을 겸비하는 Flyweight 객체 관리 클래스

- Client : 클라이언트는 FlyweightFactory를 통해 Flyweight 타입의 객체를 얻어 사용한다.

 

 

- Intrinsic State (본질적 상태) : 객체 내부에서 공유되는 불변 정보 (ex: 나무 모양, 텍스쳐)

- Extrinsic State (외적 상태) : 인스턴스마다 변하는 정보 (ex: 나무 좌표, 색상 농도)

 

 

[장점]

- 어플리케이션에서 사용하는 메모리를 줄일 수 있다.

- 프로그램 속도 개선

 

[단점]

- 코드의 복잡도 증가

 

 

ex) 폭탄 피하기 게임

ㄴ 변함: 폭탄의 위치

ㄴ 변하지 않음(캐시) : 폭탄의 형태, 색

 

 

ex) 마인크래프트 필드에 나무 심기

- mesh, texture 재사용한다!

- 위치는 모두 다르다.

 

ConcreteFlyweight (불변, 캐시) : Treemodel (메쉬, 텍스쳐...)

UnsharedConcreteFlyweight (변함) : Tree (좌표값을 가지고 있음)

//공통(변하지 않음)
class TreeModel {
	long objsize = 100; //100MB
    
    String type; //나무 종류
    Object mesh; //메쉬
    Object texture; //나무껍질+잎사귀 텍스쳐
    
    public Tree(String type, Object mesh, Object texture) {
    	...
    	Memory.size += this.objsize;
    }
}


//변함(Unshared)
class Tree {
	long objsize = 10; //10MB
    
    //위치 변수
    double position_x;
    double position_y;
    
    //나무 모델
    Treemodel model;
    
    public Tree(Treemodel model, double position_x, double position_y) {
    	...
        Memory.size += this.objsize;
    }
}
//Flyweight팩토리(관리 공장)
class TreeModelFactory {
	//treemodel 객체들을 map으로 등록하여 캐싱
    private static final Map<String, Treemodel> chche = new HashMap<>();
    
    public static Treemodel getInstance(String key) {
    	//캐시되어 있다면
        if(chche.containsKey(key)) {
        	return chche.get(key); //그대로 가져와 반환
        }
        //캐시되어있지 않다면 나무 모델 객체를 새로 생성하고 반환
        else {
        	Treemodel m = new Treemodel (
            	key,
                new Object();
                new Object();
            );
        }
        
        //캐시에 적재
        chche.put(key, model) {
        	return model;
        }
    }
}
//client
class Terrain {
    //지형타일 크기
    static final int CANVAS_SIZE = 10000;
    
    //나무를 렌더링
    public void render(String type, double position_x, double position_y) {
    	//캐시되어있는 나무모델객체 가져오기
        Treemodel m = Treemodelfactory.getInstance(type);
        
        //재사용한 나무 모델 객체와 변화하는 속성인 좌표값으로 나무 생성
        Tree t = new Tree(model, position_x, position_y);
    }
}


//main
public class main { 
    public static class main(String[] args) {
    	//지형 생성
    	Terrain terrain = new Terrain();
        
        //Oak나무 5개 생성
        for(int i = 0; i<5; i++) {
        	terrain.render(
            	"Oak",
                Math.random() * terrain.CANVAS_SIZE;
                Math.random() * terrain.CANVAS_SIZE;
            );
        }
        
        //Acacia나무 10개 생성
        for(int i = 0; i<10; i++) {
        	terrain.render(
            	"Acacia",
                Math.random() * terrain.CANVAS_SIZE;
                Math.random() * terrain.CANVAS_SIZE;
            );
        }
        
        //Jungle나무 6개 생성
        for(int i = 0; i<6; i++) {
        	terrain.render(
            	"Jungle",
                Math.random() * terrain.CANVAS_SIZE;
                Math.random() * terrain.CANVAS_SIZE;
            );
        }
    }
}

 

 

[실사용 사례]

- Java의 String

String s1 = "hello"
String s2 = "hello"

* == 비교하면 true나옴!(같은 주소값을 가리킴) (hello라는 문자열 객체를 하나만 만들어 공유하기 때문에)