학습일지/Language

[Design Pattern] FlyWeight

inspirit941 2020. 12. 15. 08:06
반응형

FlyWeight 패턴

생성 비용이 큰 객체를 공통으로 사용할 수 있도록 만드는 패턴.

  • 중복 생성될 가능성이 높은 객체
    • 동일한 리소스가 자주 사용될 가능성이 높다는 의미이므로, 공통자원 형태로 관리하는 편이 효율적이다
  • 생성비용은 크지만 사용빈도는 낮은 객체
    • 이런 경우 매리 객체를 생성해두는 건 낭비. 요청이 있을 때에만 생성해서 제공한다.

FlyWeight 패턴은 위 두 가지 목적을 위해 존재함.

객체 생성을 담당하는 Factory 역할과 객체 관리 역할을 분리하는 편이 유용한 경우도 있으나, 일반적으로는 역할의 크기가 크게 다르지 않으므로 하나의 클래스 안에 있어도 무방하다.

장점

  • 많은 객체를 생성할 때 생성시간 / 메모리소모를 줄일 수 있음
  • state pattern과 결합이 용이함

단점

  • 개별 설정이 불가능. 공통요소의 일부를 빼서 수정하는 식의 설정이 불가능하다.

사용예시

  • 워드프로세서의 문자 그래픽 표현을 위한 자료구조
  • JDK
    • String. (String pool)
    • Integer / Boolean / Character / Byte의 ValueOf(). 캐시메모리 확인해서 객체가 있으면 불러오고, 없으면 새로 생성하는 식으로 동작함. primitive값을 boxing하는 것보다 빠르다.
public class TestString1 {
    public static void main(String[] args) {
        String str1 = new String("test");
        String str2 = new String("test");
        String str3 = "test";
        String str4 = "test";
        // 여기서 str1과 str2는 서로 다른 객체를 참조하지만
        // str3, str4는 같은 객체를 참조한다.
        // 중복 생성을 막기 위해 str3, str4에는 flyweight 패턴이 적용된 사례
    }
}

public class TestString1 {
    public static void main(String[] args) {
        var data1 = new MyData();
        data1.x = 10;
        data1.y = 11;
        data1.name = "test";

        var data2 = new MyData();
        // data2와 data1은 동일한 객체를 참조하게 된다.
        data2 = data1;

        // data3은 완전히 다른 객체를 참조.
        var data3 = new MyData();
        data3.x = 20;
        data3.y = 22;
        data3.name = "test2";

        // 동일한 객체를 참조하므로, data1의 name도 바뀐다.
        data2.name = "test3";
        data2.x = 7;

        // 얕은 복사 = flyweight 패턴이 적용된 사례.
    }
}

class MyData {
    int x;
    int y;
    String name;
}
public class Subject {
    private String name;

    public Subject(String name) {
        this.name = name;
    }
}

// 리소스 Subject의 생성을 관리하는 객체
public class FlyWeightFactory {
    private static Map<String, Subject> map = new HashMap<String, Subject>();

    public Subject getSubject(String key) {
        Subject subject = map.get(key);
        if (subject ==  null){
            subject = new Subject(key);
            map.put(key, subject);
            System.out.println(key +" 새로 생성");
        }
        else {
            System.out.println(key + " 값 리턴");
        }
        return subject;
    }
}

public class TestFlyWeight2 {
    public static void main(String[] args) {
        FlyWeightFactory flyWeight = new FlyWeightFactory();
        flyWeight.getSubject("a");
        flyWeight.getSubject("a");
        flyWeight.getSubject("b");
    }
}
반응형