享元模式

享元模式

享元模式Flyweight Pattern主要用于减少创建对象的数量,以减少内存占用和提高性能,其提供了减少对象数量从而改善应用所需的对象结构的方式,享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。享元模式运用共享技术有效地支持大量细粒度对象的复用,系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用,由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,其是一种对象结构型模式。

描述

面向对象技术可以很好地解决一些灵活性或可扩展性问题,但在很多情况下需要在系统中增加类和对象的个数,当对象数量太多时,将导致运行代价过高,带来性能下降等问题。享元模式正是为解决这一类问题而诞生的,享元模式通过共享技术实现相同或相似对象的重用。在享元模式中可以共享的相同内容称为内部状态IntrinsicState,而那些需要外部环境来设置的不能共享的内容称为外部状态Extrinsic State,由于区分了内部状态和外部状态,因此可以通过设置不同的外部状态使得相同的对象可以具有一些不同的特征,而相同的内部状态是可以共享的。在享元模式中通常会出现工厂模式,需要创建一个享元工厂来负责维护一个享元池Flyweight Pool用于存储具有相同内部状态的享元对象。在享元模式中共享的是享元对象的内部状态,外部状态需要通过环境来设置。在实际使用中,能够共享的内部状态是有限的,因此享元对象一般都设计为较小的对象,它所包含的内部状态较少,这种对象也称为细粒度对象,享元模式的目的就是使用共享技术来实现大量细粒度对象的复用。

模式结构

  • Flyweight: 抽象享元类。
  • ConcreteFlyweight: 具体享元类。
  • UnsharedConcreteFlyweight: 非共享具体享元类。
  • FlyweightFactory: 享元工厂类。

优点

  • 享元模式的优点在于它可以极大减少内存中对象的数量,使得相同对象或相似对象在内存中只保存一份。
  • 享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享。

缺点

  • 享元模式使得系统更加复杂,需要分离出内部状态和外部状态,这使得程序的逻辑复杂化。
  • 为了使对象可以共享,享元模式需要将享元对象的状态外部化,而读取外部状态使得运行时间变长。

适用环境

  • 一个系统有大量相同或者相似的对象,由于这类对象的大量使用,造成内存的大量耗费。
  • 对象的大部分状态都可以外部化,可以将这些外部状态传入对象中。
  • 使用享元模式需要维护一个存储享元对象的享元池,而这需要耗费资源,因此应当在多次重复使用享元对象时才值得使用享元模式。

实现

class Tea { // 茶产品类 实例为被共用的对象
    constructor(preference){
        this.preference = preference;
    }
}

class TeaMaker { // 作为茶工厂以创建茶的实例 即享元工厂来负责维护一个享元池
    constructor(){
        this.availableTea = {};
    }

    make(preference) {
        this.availableTea[preference] = this.availableTea[preference] || (new Tea());
        return this.availableTea[preference];
    }
}

(function TeaShop(){
    const shop = new TeaMaker();
    var lessSugar1 = shop.make("less sugar");
    var moreMilk1 = shop.make("more milk");
    var withoutSugar1 = shop.make("without sugar");
    var lessSugar2 = shop.make("less sugar");
    var moreMilk2 = shop.make("more milk");
    var withoutSugar3 = shop.make("without sugar");
    console.log(lessSugar1 === lessSugar2); // true
    console.log(moreMilk1 === moreMilk2); // true
    console.log(withoutSugar1 === withoutSugar3); // true
})();

每日一题

https://github.com/WindrunnerMax/EveryDay

参考

https://www.runoob.com/design-pattern/flyweight-pattern.html
https://github.com/sohamkamani/javascript-design-patterns-for-humans#-flyweight
https://design-patterns.readthedocs.io/zh_CN/latest/structural_patterns/flyweight.html

相关文章

什么是设计模式一套被反复使用、多数人知晓的、经过分类编目...
单一职责原则定义(Single Responsibility Principle,SRP)...
动态代理和CGLib代理分不清吗,看看这篇文章,写的非常好,强...
适配器模式将一个类的接口转换成客户期望的另一个接口,使得...
策略模式定义了一系列算法族,并封装在类中,它们之间可以互...
设计模式讲的是如何编写可扩展、可维护、可读的高质量代码,...