JavaScript设计模式「基于ES2024」:结构型模式-享元模式

82 阅读1分钟

享元模式是通过共享来有效地支持大量细粒度对象。这种模式通过共享来最小化内存使用或计算开销,适用于需要创建大量相似对象的场景。

// 享元类(字符属性)
class CharacterStyle {
    constructor(font, size, color) {
        this.font = font;
        this.size = size;
        this.color = color;
    }

    render(char) {
        console.log(`Rendering '${char}' in ${this.font} ${this.size}px ${this.color}`);
    }
}

// 享元工厂
class CharacterStyleFactory {
    static #styles = new Map();

    static getStyle(font, size, color) {
        const key = `${font}-${size}-${color}`;
        if (!this.#styles.has(key)) {
            this.#styles.set(key, new CharacterStyle(font, size, color));
        }
        return this.#styles.get(key);
    }

    static get stylesCount() {
        return this.#styles.size;
    }
}

// 上下文类(具体字符)
class Character {
    #char;
    #style;
    #x;
    #y;

    constructor(char, x, y, font, size, color) {
        this.#char = char;
        this.#x = x;
        this.#y = y;
        this.#style = CharacterStyleFactory.getStyle(font, size, color);
    }

    render() {
        console.log(`Character at (${this.#x}, ${this.#y}):`);
        this.#style.render(this.#char);
    }
}

// 文本编辑器类
class TextEditor {
    #characters = [];

    addCharacter(char, x, y, font, size, color) {
        this.#characters.push(new Character(char, x, y, font, size, color));
    }

    render() {
        this.#characters.forEach(char => char.render());
    }
}

// 使用示例
function demonstrateFlyweight() {
    const editor = new TextEditor();

    // 添加一些字符
    editor.addCharacter('H', 0, 0, 'Arial', 12, 'black');
    editor.addCharacter('e', 10, 0, 'Arial', 12, 'black');
    editor.addCharacter('l', 20, 0, 'Arial', 12, 'black');
    editor.addCharacter('l', 30, 0, 'Arial', 12, 'black');
    editor.addCharacter('o', 40, 0, 'Arial', 12, 'black');
    editor.addCharacter('W', 60, 0, 'Times New Roman', 14, 'red');
    editor.addCharacter('o', 80, 0, 'Times New Roman', 14, 'red');
    editor.addCharacter('r', 90, 0, 'Times New Roman', 14, 'red');
    editor.addCharacter('l', 100, 0, 'Times New Roman', 14, 'red');
    editor.addCharacter('d', 110, 0, 'Times New Roman', 14, 'red');

    // 渲染所有字符
    editor.render();

    // 显示创建的样式数量
    console.log(`\nTotal number of character styles created: ${CharacterStyleFactory.stylesCount}`);
}

demonstrateFlyweight();

实现思路

  1. CharacterStyle 类(享元)

    • 包含字符的内在状态(字体、大小、颜色)。
    • 提供 render 方法来渲染字符。
  2. CharacterStyleFactory 类(享元工厂)

    • 使用静态私有字段 #styles 来存储已创建的样式。
    • 提供 getStyle 方法来获取或创建样式,确保相同的样式只被创建一次。
    • 提供 stylesCount getter 来获取创建的样式数量。
  3. Character 类(上下文)

    • 包含字符的外在状态(字符值、位置)。
    • 引用一个 CharacterStyle 对象来渲染字符。
  4. TextEditor

    • 管理多个 Character 对象。
    • 提供方法来添加字符和渲染整个文本。

优点

  • 内存优化:通过共享 CharacterStyle 对象,大大减少了内存使用。
  • 性能提升:减少了对象创建的次数,可能提高性能。
  • 透明性:客户端代码不需要知道享元模式的存在。
  • 可扩展性:可以轻松添加新的字符样式而不影响现有代码。