디자인패턴 (FlyWeight)

백종현·2023년 6월 24일
0

FlyWeight 패턴

문제

이미 사용되고 있는 정보에 대해서 계속해서 new를 통해 객체를 만들게 되면, 메모리에 계속해서 낭비가 생긴다.

위의 경우는, 위치정보나 벡터, 스피드의 경우는 가변적이지만, color와 sprite는 불변적이다. 하지만 new를 통해 인스턴스를 만들 때마다 이미 존재하는 정보에 대해 중복이 발생하고, 메모리 사용량이 증가하게 된다.

개념

인스턴스를 최대한 공유하고, 쓸데없이 new를 해서 메모리를 많이 사용하지 않도록 하는 패턴. 미리 만들어진 인스턴스를 이용하여 공유하는 패턴이다.

코드

이름설명
BigChar큰 문자를 나타내는 클래스
BigCharFactoryBigChar의 인스턴스를 공유, 생성하는 클래스
BigStringBigChar를 모아서 만든 '큰 문자열'을 나타내는 클래스
Main동작 테스트 용 클래스
# big0.txt 예시
....######......
..##......##....
..##......##....
..##......##....
..##......##....
..##......##....
....######......
................
public class BigChar {
    // 문자의 이름 
    private char charname;
    // 큰 문자를 표현하는 문자열('#' '.' '\n'으로 이루어진 열)
    private String fontdata;

    // 생성자 
    public BigChar(char charname) {
        this.charname = charname;
        try {
            String filename = "big" + charname + ".txt";
            StringBuilder sb = new StringBuilder();
            for (String line: Files.readAllLines(Path.of(filename))) {
                sb.append(line);
                sb.append("\n");
            }
            this.fontdata = sb.toString();
        } catch (IOException e) {
            this.fontdata = charname + "?";
        }
    }

    // 큰 문자를 표시한다
    public void print() {
        System.out.print(fontdata);
    }
}
public class BigCharFactory {
    // 이미 만든 BigChar 인스턴스를 관리 
    private Map<String,BigChar> pool = new HashMap<>();
    // Singleton 패턴 
    private static BigCharFactory singleton = new BigCharFactory();

    // 생성자 
    private BigCharFactory() {
    }

    // 유일한 인스턴스를 얻는다
    public static BigCharFactory getInstance() {
        return singleton;
    }

    // BigChar 인스턴스 생성(공유)
    public synchronized BigChar getBigChar(char charname) {
        BigChar bc = pool.get(String.valueOf(charname));
        if (bc == null) {
            // 여기서 BigChar 인스턴스를 생성 
            bc = new BigChar(charname);
            pool.put(String.valueOf(charname), bc);
        }
        return bc;
    }
}
public class BigString {
    // '큰 문자'의 배열
    private BigChar[] bigchars;

    // 생성자 
    public BigString(String string) {
        BigCharFactory factory = BigCharFactory.getInstance();
        bigchars = new BigChar[string.length()];
        for (int i = 0; i < bigchars.length; i++) {
            bigchars[i] = factory.getBigChar(string.charAt(i));
        }
    }

    // 표시
    public void print() {
        for (BigChar bc: bigchars) {
            bc.print();
        }
    }
}
public class Main {
    public static void main(String[] args) {
        BigString bs = new BigString("323");
        bs.print();
    }
}
/*
결과 :
................
....######......
..##......##....
..........##....
......####......
..........##....
..##......##....
....######......
................
....######......
..##......##....
..........##....
......####......
....##..........
..##............
..##########....
................
....######......
..##......##....
..........##....
......####......
..........##....
..##......##....
....######......
................

Process finished with exit code 0

*/

BigCharFactory에서 Map을 통해 여러번 사용되는 객체를 공유하게 된다.

FlyWeight 패턴의 요소

Flyweight(플라이급) 역할 : 평소처럼 다루면 프로그램이 무거워지기 때문에, 공유하는 편이 나은 것을 나타낸다. 예제 프로그램에서는 BigChar이다.
FlyweightFactory(플라이급 공장) 역할 : Flyweight를 만드는 클래스이며, 이 클래스를 사용하여 Flyweight의 인스턴스를 공유하도록 한다. 예제 프로그램에서는 BigCharFatory이다.
Client(의뢰자)의 역할 : 실제로 FlyweightFactory를 이용하여 Flyweight를 만들어 활용하는 클래스이다. 위에서 BigString 클래스가 이 역할이다.

왜 FlyWeight를 사용할까?

여러 장소에 영향을 미친다. 하나의 인스턴스가 여러 곳에서 공유되므로, 이 인스턴스에 변경이 일어나면 여러 곳에 영향을 미칠 수 있다. 따라서 이는 장점이 될 수도 있고, 단점이 될 수도 있기 때문에 고려를 잘 해야한다.

이 패턴을 사용하는 것은 메모리 사용량을 줄일 수 있다. 또한 추가적으로 new를 통해 인스턴스를 생성하는 시간 또한 줄일 수 있으므로 메모리 외의 리소스를 줄이는 효과도 얻을 수 있다.

추가

공유하는 정보를 intrinsic한 정보라고 하고, 공유하지 않는 정보를 extrinsic한 정보라고 한다.

Flyweight는 공통 속성이 공유 된 플라이급 객체로 분해하는 '객체 정규화 기술'이라고 할수 있다. 중복성을 최소화하려는 데이터 모델 정규화와 유사하다.

참조 :
Java 언어로 배우는 디자인 패턴 입문

profile
노력하는 사람

0개의 댓글