플라이웨이트 패턴

소프트웨어 디자인 패턴

플라이웨이트 패턴(Flyweight pattern)는 동일하거나 유사한 객체들 사이에 가능한 많은 데이터를 서로 공유하여 사용하도록 하여 메모리 사용량을 최소화하는 소프트웨어 디자인 패턴이다. 종종 오브젝트의 일부 상태 정보는 공유될 수 있는데, 플라이웨이트 패턴에서는 이와 같은 상태 정보를 외부 자료 구조에 저장하여 플라이웨이트 오브젝트가 잠깐 동안 사용할 수 있도록 전달한다.

편집

자바 편집

public enum FontEffect {
    BOLD, ITALIC, SUPERSCRIPT, SUBSCRIPT, STRIKETHROUGH
}

public final class FontData {
    /**
     * A weak hash map will drop unused references to FontData.
     * Values have to be wrapped in WeakReferences,
     * because value objects in weak hash map are held by strong references.
     */
    private static final WeakHashMap<FontData, WeakReference<FontData>> flyweightData =
        new WeakHashMap<FontData, WeakReference<FontData>>();
    private final int pointSize;
    private final String fontFace;
    private final Color color;
    private final Set<FontEffect> effects;

    private FontData(int pointSize, String fontFace, Color color, EnumSet<FontEffect> effects) {
        this.pointSize = pointSize;
        this.fontFace = fontFace;
        this.color = color;
        this.effects = Collections.unmodifiableSet(effects);
    }

    public static FontData create(int pointSize, String fontFace, Color color,
        FontEffect... effects) {
        EnumSet<FontEffect> effectsSet = EnumSet.noneOf(FontEffect.class);
        for (FontEffect fontEffect : effects) {
            effectsSet.add(fontEffect);
        }
        // 객체를 생성하는 데 드는 비용이나 객체가 차지하는 메모리 공간에 대해 걱정할 필요가 없다.
        FontData data = new FontData(pointSize, fontFace, color, effectsSet);
        if (!flyweightData.containsKey(data)) {
            flyweightData.put(data, new WeakReference(data));
        }
        // 해시값에 따라 변경불가능한 단일본을 리턴한다.
        return flyweightData.get(data).get();
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof FontData) {
            if (obj == this) {
                return true;
            }
            FontData other = (FontData) obj;
            return other.pointSize == pointSize && other.fontFace.equals(fontFace)
                && other.color.equals(color) && other.effects.equals(effects);
        }
        return false;
    }

    @Override
    public int hashCode() {
        return (pointSize * 37 + effects.hashCode() * 13) * fontFace.hashCode();
    }

    // Getters for the font data, but no setters. FontData is immutable.
}

C# 편집

using System.Collections;
using System.Collections.Generic;
using System;

class GraphicChar {
    char c;
    string fontFace;
    public GraphicChar(char c, string fontFace) { this.c = c; this.fontFace = fontFace; }
    public static void printAtPosition(GraphicChar c, int x, int y)   {
        Console.WriteLine("Printing '{0}' in '{1}' at position {2}:{3}.", c.c, c.fontFace, x, y);
    }
}

class GraphicCharFactory {
    Hashtable pool = new Hashtable(); // the Flyweights

    public int getNum() { return pool.Count; }

    public GraphicChar get(char c, string fontFace) {
        GraphicChar gc;
        string key = c.ToString() + fontFace;
        gc = pool[key] as GraphicChar;
        if (gc == null) {
            gc = new GraphicChar(c, fontFace);
            pool.Add(key, gc);
        }
        return gc;
    }
}

class FlyWeightExample {
    public static void Main(string[] args) {
        GraphicCharFactory cf = new GraphicCharFactory();

        // Compose the text by storing the characters as objects.
        List<GraphicChar> text = new List<GraphicChar>();
        text.Add(cf.get('H', "Arial"));    // 'H' and "Arial" are called intrinsic information
        text.Add(cf.get('e', "Arial"));    // because it is stored in the object itself.
        text.Add(cf.get('l', "Arial"));
        text.Add(cf.get('l', "Arial"));
        text.Add(cf.get('o', "Times"));

        // See how the Flyweight approach is beginning to save space:
        Console.WriteLine("CharFactory created only {0} objects for {1} characters.", cf.getNum(), text.Count);

        int x=0, y=0;
        foreach (GraphicChar c in text) {             // Passing position as extrinsic information to the objects,
            GraphicChar.printAtPosition(c, x++, y);   // as a top-left 'A' is not different from a top-right one.
        }
    }
}