플라이웨이트 패턴

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

예

자바 
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.
        }
    }
}

소프트웨어 디자인 패턴
소프트웨어 최적화