Flyweight Pattern

Definition

Use sharing to support large numbers of fine-grained objects efficiently.

Explanation

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. Often some parts of the object state can be shared, and it is common practice to hold 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.

Screencast

TypeScript Code

module Flyweight {
    interface IWriter {
        write(content: string): void;
    }

    enum Style {
        Block,
        Inline
    }

    enum Color {
        Red,
        Green,
        Blue
    }

    class Writer {
        constructor(public tagName: string, public color: Color) {
        }

        write(content: string) {
            Output.Write("<" + this.tagName + " style='color:" + Color[this.color] + "'>" +
                content +
                "");
        }
    }

    class BlockWriter extends Writer {
        constructor(color: Color) {
            super("div", color);
        }
    }

    class InlineWriter extends Writer {
        constructor(color: Color) {
            super("span", color);
        }
    }

    class FlyWeightWriterFactory {
        static _elements = {};
        static getWriter(style: Style, color: Color): IWriter {
            var key = style.toString() + color.toString();
            if (!this._elements[key]) {
                switch (style) {
                    case Style.Block:
                        this._elements[key] = new BlockWriter(color);
                        break;
                    case Style.Inline:
                        this._elements[key] = new InlineWriter(color);
                        break;
                }
            }

            var retVal = this._elements[key];
            return retVal;
        }
    }

    class HtmlElement {
        private writer: IWriter;
        constructor(style: Style, color: Color) {
            this.writer = FlyWeightWriterFactory.getWriter(style, color);
        }

        private _content: string;
        public get content(): string {
            return this._content;
        }

        public set content(value: string) {
            this._content = value;
        }

        public write():void {
            this.writer.write(this.content);
        }
    }

    window.addEventListener("load", function () {
        for (var i = 0; i < 100; i++) {
            var style = Math.floor(Math.random() * 2);
            var color = Math.floor(Math.random() * 3);

            var element = new HtmlElement(style, color);
            element.content = "This element uses a flyweight for rendering!";
            element.write();
        }
    });
}

Output