Jump to content

Flyweight pattern: Difference between revisions

From Wikipedia, the free encyclopedia
Content deleted Content added
Examples: add warning re excess examples and link to Wikibooks
Line 102: Line 102:
*Article "[http://www.javaworld.com/javaworld/jw-07-2003/jw-0725-designpatterns.html Make your apps fly - Implement Flyweight to improve performance]" by [[David Geary]]
*Article "[http://www.javaworld.com/javaworld/jw-07-2003/jw-0725-designpatterns.html Make your apps fly - Implement Flyweight to improve performance]" by [[David Geary]]
*Article "[http://theserverside.com/articles/article.tss?l=Caching Enhancing Web Application Performance with Caching]" by [[Neal Ford]]
*Article "[http://theserverside.com/articles/article.tss?l=Caching Enhancing Web Application Performance with Caching]" by [[Neal Ford]]
*Article "[http://www.codeproject.com/KB/architecture/testvalidators.aspx The Flyweight Pattern]" by [[Alberto Bar-Noy]]
*Sample Chapter "[http://www.informit.com/articles/article.aspx?p=31563 C# Design Patterns: The Flyweight Pattern]" by [[James W. Cooper]]
*Sample Chapter "[http://www.informit.com/articles/article.aspx?p=31563 C# Design Patterns: The Flyweight Pattern]" by [[James W. Cooper]]
*Section "[http://web.archive.org/web/20070404160614/http://btl.usc.edu/rides/documentn/refMan/rf21_d.html Flyweight Text Entry Fields (archive.org)]" from the [[RIDES]] Reference Manual by [[Allen Munro]] and [[Quentin A. Pizzini]]
*Section "[http://web.archive.org/web/20070404160614/http://btl.usc.edu/rides/documentn/refMan/rf21_d.html Flyweight Text Entry Fields (archive.org)]" from the [[RIDES]] Reference Manual by [[Allen Munro]] and [[Quentin A. Pizzini]]
*[http://c2.com/cgi/wiki?FlyweightPattern Description] from Portland's Pattern Repository
*[http://c2.com/cgi/wiki?FlyweightPattern Description] from Portland's Pattern Repository
*[http://dofactory.com/Patterns/PatternFlyweight.aspx Overview]
*[http://sourdough.phpee.com/index.php?node=18 Sourdough Design]
*[http://sourdough.phpee.com/index.php?node=18 Sourdough Design]
*[http://www.allapplabs.com/java_design_patterns/flyweight_pattern.htm Structural Patterns - Flyweight Pattern]
*[http://www.allapplabs.com/java_design_patterns/flyweight_pattern.htm Structural Patterns - Flyweight Pattern]
*[http://www.perlmonks.org/?node_id=94783 Class::Flyweight - implement the flyweight pattern in OO perl]
*[http://www.perlmonks.org/?node_id=94783 Class::Flyweight - implement the flyweight pattern in OO perl]
*[http://boost.org/libs/flyweight/index.html Boost.Flyweight - A generic C++ implementation]
*[http://boost.org/libs/flyweight/index.html Boost.Flyweight - A generic C++ implementation]
*[http://www.dofactory.com/Patterns/PatternFlyweight.aspx A C# definition and example]


{{Design Patterns Patterns}}
{{Design Patterns Patterns}}

Revision as of 01:31, 12 February 2011

Flyweight is a software design pattern. A flyweight is an object that minimizes memory use by sharing as much data as possible with other similar objects; it is a way to use objects in large numbers when a simple repeated representation would use an unacceptable amount of memory. The term is named after the boxing weight class. Often some parts of the object state can be shared and it's common to put them in external data structures and pass them to the flyweight objects temporarily when they are used.

A classic example usage of the flyweight pattern is the data structures for graphical representation of characters in a word processor. It might be desirable to have, for each character in a document, a glyph object containing its font outline, font metrics, and other formatting data, but this would amount to hundreds or thousands of bytes for each character. Instead, for every character there might be a reference to a flyweight glyph object shared by every instance of the same character in the document; only the position of each character (in the document and/or the page) would need to be stored internally.

In other contexts the idea of sharing identical data structures is called hash consing.

Example

The following programs illustrate the document example given above: the flyweights are called FontData in the Java example.

The examples illustrate the flyweight pattern used to reduce memory by loading only the data necessary to perform some immediate task from a large Font object into a much smaller FontData (flyweight) object.

import java.lang.ref.WeakReference;
import java.util.WeakHashMap;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Set;
import java.awt.Color;

public final class FontData {

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

    /**
     * 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>> FLY_WEIGHT_DATA =
        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);
        }
        // We are unconcerned with object creation cost, we are reducing overall memory consumption
        FontData data = new FontData(pointSize, fontFace, color, effectsSet);

        FontData result = null;
        // Retrieve previously created instance with the given values if it (still) exists
        WeakReference<FontData> ref = FLY_WEIGHT_DATA.get(data);
        if (ref != null) {
            result = ref.get();
        }

        // Store new font data instance if no matching instance exists
        if(result == null){      	
            FLY_WEIGHT_DATA.put(data, new WeakReference<FontData> (data));
            result = data;
        }

        // return the single immutable copy with the given values
        return result;
    }

    @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.
}