플라이웨이트 패턴

플라이웨이트 패턴(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. } 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. } } } 메모이제이션