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

박세건·2024년 5월 20일
0

디자인 패턴

목록 보기
3/17
post-thumbnail

플리웨이트 패턴이란, 변하지 않는 속성과 자주 변하는 속성을 분리해서 변하지 않는 속성을 재사용 가능한 객체 인스턴스로 공유시켜 메모리 사용량을 최소화하는 구조패턴이다.
중요한점은 캐시 개념을 적용시켜서 코드로 패턴화 한것이다(ex, Map 자료구조를 사용해서 이전에 생성했던 정보를 기억)

이름에 알 수 있듯이 메모리를 가볍게 만든다는 의미로 쓰인다.
Flyweight = 경량
경량 패턴이라고도 불린다.

구조

  • Flyweight : 경량 객체를 묶는 인터페이스
  • FlyweightFactory : 경량 객체를 제공해주는 공장 역할
    • 객체가 존재하면 그대로 반환하고 없다면 새로 생성 후 반환
  • Client : FlyweightFactory로 부터 객체를 얻어서 사용
  • intrinsic : 고유한, 공유해도 문제 없음, 변하지 않음
  • extrinsic : 외적인, 공유 불가, 상황에 따라 변함

추가설명

예를 들어서 폭탄 떨어뜨리기 게임을 생각하자, 폭탄이라는 객체는 중복되서 사용되게 된다.
하지만 폭탄의 모양이나 색은 고정값으로 공유가 가능하지만 좌표값은 모든 폭탄에 따라 다르게 변화하기 때문에 공유될 수 없다.
폭탄의 형태나 색을 포함하는 객체 : ConcreteFlyweight
좌표값을 포함하는 객체 : UnsharedConcreteFlyweight
폭탄을 생성하는 객체 : FlyweightFactory

추가에 추가 설명

  • 만약 여러 모양의 폭탄의 모양이 여러개이고 색도 여러개라고 설정하자
  • 그럼에도 폭탄의 모양과 색이 중복되는 경우가 존재할 것이다
  • 그럴때 폭탄의 모양과 색의 속성을 담당하는 객체(BombInfo)를 하나 설계하고 Bomb 이라는 객체가 BombInfo를 갖고 있도록 합성 시켜준다
  • 여기서 중요한 점은 모양과 색의 조합에 따른 키 값이 정해진다는 점이다
    • ex) 네모 + 빨간 = 0, 네모 + 노랑 = 1, 동그라미 + 빨간 10....
  • BombInfoFactory는 BombInfo를 위에서 정한 key 값을 받아서 BombInfo를 생성해준다.
    • 이때 Map 자료구조를 사용해서 Map<String,BombInfo> cache 를 이용해 반환시켜준다
  • 만약 key값이 Map에 존재하지 않다면 그 값에 맞는 새로운 BombInfo를 생성하고 캐시를 등록 해주고 반환해준다
  • 이렇게 모든 폭탄을 생성하는 방법보다 메모리를 줄일 수 있게된다.

사용 시기

  • 생성되는 객체의 수가 많아서 비용이 높아질때
  • 공통적인 인스턴스를 많이 생성하는 로직이 있을 경우
  • 생성된 객체가 오래도록 메모리에 머무르는 경우가 많을때

장점

  • 메모리 줄임
  • 프로그램 속도 개선

단점

  • 코드 복잡도 증가

예시

나무의 공통되는 속성들을 TreeModel 클래스로 관리

// ConcreteFlyweight - 플라이웨이트 객체는 불변성을 가져야한다. 변경되면 모든 것에 영향을 주기 때문이다.
final class TreeModel {
    // 메시, 텍스쳐 총 사이즈
    long objSize = 90; // 90MB

    String type; // 나무 종류
    Object mesh; // 메쉬
    Object texture; // 나무 껍질 + 잎사귀 텍스쳐

    public TreeModel(String type, Object mesh, Object texture) {
        this.type = type;
        this.mesh = mesh;
        this.texture = texture;

        // 나무 객체를 생성하여 메모리에 적재했으니 메모리 사용 크기 증가
        Memory.size += this.objSize;
    }
}

//UnsahredConcreteFlyweight
class Tree {
    // 죄표값과 나무 모델 참조 객체 크기를 합친 사이즈
    long objSize = 10; // 10MB

    // 위치 변수
    double position_x;
    double position_y;

    // 나무 모델
    TreeModel model;

    public Tree(TreeModel model, double position_x, double position_y) {
        this.model = model;
        this.position_x = position_x;
        this.position_y = position_y;

        // 나무 객체를 생성하였으니 메모리 사용 크기 증가
        Memory.size +=  this.objSize;
    }
}

// FlyweightFactory
class TreeModelFactory {
    // Flyweight Pool - TreeModel 객체들을 Map으로 등록하여 캐싱
    private static final Map<String, TreeModel> cache = new HashMap<>(); // static final 이라 Thread-Safe 함

    // static factory method
    public static TreeModel getInstance(String key) {
        // 만약 캐시 되어 있다면
        if(cache.containsKey(key)) {
            return cache.get(key); // 그대로 가져와 반환
        } else {
            // 캐시 되어있지 않으면 나무 모델 객체를 새로 생성하고 반환
            TreeModel model = new TreeModel(
                    key,
                    new Object(),
                    new Object()
            );
            System.out.println("-- 나무 모델 객체 새로 생성 완료 --");

            // 캐시에 적재
            cache.put(key, model);

            return model;
        }
    }
}
profile
멋있는 사람 - 일단 하자

0개의 댓글