TypeScript设计模式之享元模式

更新日期: 2019-12-22阅读: 1.6k标签: 模式

享元模式就是运行共享技术有效地支持大量细粒度的对象,避免大量拥有相同内容的小类的开销(如耗费内存),使大家共享一个类。在享元模式中有两个重要的概念,即内部状态和外部状态:

  • 内部状态:在享元对象内部不随外界环境改变而改变的共享部分。
  • 外部状态:随着环境的改变而改变,不能够共享的状态就是外部状态。

由于享元模式区分了内部状态和外部状态,所以我们可以通过设置不同的外部状态使得相同的对象可以具备一些不同的特性,而内部状态设置为相同部分。


一、优缺点

优点

  • 享元模式的优点在于它能够极大的减少系统中对象的个数。
  • 享元模式由于使用了外部状态,外部状态相对独立,不会影响到内部状态,所以享元模式使得享元对象能够在不同的环境被共享。

缺点

  • 由于享元模式需要区分外部状态和内部状态,使得应用程序在某种程度上来说更加复杂化了。
  • 为了使对象可以共享,享元模式需要将享元对象的状态外部化,而读取外部状态使得运行时间变长。

二、应用场景

  • 一个程序中使用了大量的相似对象。
  • 由于使用了大量对象,造成很大的内存开销。
  • 对象的大多数状态都可以变为外部状态。
  • 剥离出对象的外部状态之后,可以用相对较少的共享对象取代大量对象。


三、模式结构

享元模式包含以下角色:

  • Client:调用 FlyweightFactory 获取享元对象。
  • FlyweightFactory:
    • 创建和管理享元对象;
    • 当请求某个享元对象不存在时,它会创建一个新的享元对象;
    • 新创建的享元对象会被存储起来,用于下次请求。
  • Flyweight:维护要在应用程序之间共享的固有数据



四、实战

苹果公司批量生产 iPhone11,iPhone11 的大部分属性比如型号、屏幕都是一样,少部分属性比如内存有分 128、256G 等。未使用享元模式前,我们写如下代码

class Iphone11 {
  constructor(model: string, screen: number, memory: number, sn: number) { }
}

const phones = [];
for (let i = 0; i < 10000; i++) {
  let memory = i % 2 == 0 ? 128 : 256;
  phones.push(new Iphone11("iPhone11", 6.1, memory, i));
}

在以上代码中,我们创建了一万个 iPhone11,每个 iPhone11 都独立占有一个内存空间。 但是我们仔细观察可以看到,大部分 iPhone11 都是类似的,只是内存和序列号不一样,如果是一个对性能要求比较高的程序,我们就要考虑去优化它。

当存在大量相似对象的程序,我们就可以考虑用享元模式去优化它,我们分析出大部分的 iPhone11 的型号、屏幕、内存都是一样的,那么这部分数据就可以共用,这就是享元模式中的内在数据,因此定义 iPhone11 对应的享元类如下:

class IphoneFlyweight {
  constructor(model: string, screen: number, memory: number) {}
}

我们定义了 IphoneFlyweight 享元类,其中包含型号、屏幕、内存三个数据。我们还需要一个享元工厂来维护这些数据:

class FlyweightFactory {
    private phonesMap: { [s: string]: IphoneFlyweight } = {};

    public get(model: string, screen: number, memory: number): IphoneFlyweight {
      const key = model + screen + memory;
      if (!this.phonesMap[key]) {
        this.phonesMap[key] = new IphoneFlyweight(model, screen, memory);
      }
      return this.phonesMap[key];
    }
}

在这个工厂中,我们定义了一个对象来保存享元对象,并提供一个方法根据参数来获取享元对象,如果 phonesMap 对象中有则直接返回,没有则创建一个返回。

具体实现


定义 IphoneFlyweight 类

/**
 * 内部状态:model, screen, memory
 * 外部状态:sn
 */
class IphoneFlyweight {
  constructor(model: string, screen: number, memory: number) { }
}

定义 FlyweightFactory 类

class FlyweightFactory {
  private phonesMap: { [s: string]: IphoneFlyweight } = {};

  public get(model: string, screen: number, memory: number): IphoneFlyweight {
    const key = model + screen + memory;
    if (!this.phonesMap[key]) {
      this.phonesMap[key] = new IphoneFlyweight(model, screen, memory);
    }
    return this.phonesMap[key];
  }
}

定义 Iphone 类

class Iphone {
  constructor(flyweight: IphoneFlyweight, sn: number) { }
}

定义 IphoneFactory 类

class IphoneFactory {
  private static flyweightFactory: FlyweightFactory = new FlyweightFactory();

  public getIphone(
    model: string,
    screen: number,
    memory: number,
    sn: number
  ) {
    const flyweight: IphoneFlyweight = IphoneFactory.flyweightFactory.get(
      model,
      screen,
      memory
    );
    return new Iphone(flyweight, sn);
  }
}

使用示例

function show(): void {
  const iphoneFactory = new IphoneFactory();
  const phones = [];
  for (let i = 0; i < 10000; i++) {
    let memory = i % 2 == 0 ? 128 : 256;
    phones.push(iphoneFactory.getIphone("iPhone11", 6.1, memory, i));
  }
  console.log("Already created 10000 iPhone11");
}

最后我们来看一下未使用享元模式(左图)和使用享元模式(右图)的代码:


由于享元模式区分了内部状态和外部状态,所以我们可以通过设置不同的外部状态使得相同的对象可以具备一些不同的特性,而内部状态设置为相同部分。

在前面的 iPhone 示例中,我们定义了 IphoneFlyweight 享元类,其中包含型号、屏幕、内存三个内部状态。而对于外部状态如手机编号 sn,我们重新定义另一个 Iphone 类来包含该外部状态。在创建 Iphone 对象时,在型号、屏幕和内存相同的情况下,会共享由 IphoneFlyweight 享元类创建的享元对象。


五、总结

享元模式(Flyweight Pattern)主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式。


链接: https://www.fly63.com/article/detial/7346

js设计模式之单例模式,javascript如何将一个对象设计成单例

单例模式是我们开发中一个非常典型的设计模式,js单例模式要保证全局只生成唯一实例,提供一个单一的访问入口,单例的对象不同于静态类,我们可以延迟单例对象的初始化,通常这种情况发生在我们需要等待加载创建单例的依赖。

前端设计模式:从js原始模式开始,去理解Js工厂模式和构造函数模式

工厂模式下的对象我们不能识别它的类型,由于typeof返回的都是object类型,不知道它是那个对象的实例。另外每次造人时都要创建一个独立的person的对象,会造成代码臃肿的情况。

JavaScript设计模式_js实现建造者模式

建造者模式:是将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象

html和xhtml,DOCTYPE和DTD,标准模式和兼容模式

主要涉及知识点: HTML与XHTML,HTML与XHTML的区别,DOCTYPE与DTD的概念,DTD的分类以及DOCTYPE的声明方式,标准模式(Standard Mode)和兼容模式(Quircks Mode),标准模式(Standard Mode)和兼容模式(Quircks Mode)的区别

前端四种设计模式_JS常见的4种模式

JavaScript中常见的四种设计模式:工厂模式、单例模式、沙箱模式、发布者订阅模式

javascript 策略模式_理解js中的策略模式

javascript 策略模式的定义是:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。 策略模式利用组合,委托等技术和思想,有效的避免很多if条件语句,策略模式提供了开放-封闭原则,使代码更容易理解和扩展, 策略模式中的代码可以复用。

javascript观察者模式_深入理解js中的观察者模式

javascript观察者模式又叫发布订阅模式,观察者模式的好处:js观察者模式支持简单的广播通信,自动通知所有已经订阅过的对象。存在一种动态关联,增加了灵活性。目标对象与观察者之间的抽象耦合关系能够单独扩展以及重用。

Vue中如何使用方法、计算属性或观察者

熟悉 Vue 的都知道 方法methods、计算属性computed、观察者watcher 在 Vue 中有着非常重要的作用,有些时候我们实现一个功能的时候可以使用它们中任何一个都是可以的

我最喜欢的 JavaScript 设计模式

我觉得聊一下我爱用的 JavaScript 设计模式应该很有意思。我是一步一步才定下来的,经过一段时间从各种来源吸收和适应直到达到一个能提供我所需的灵活性的模式。让我给你看看概览,然后再来看它是怎么形成的

Flutter 设计模式 - 简单工厂

在围绕设计模式的话题中,工厂这个词频繁出现,从 简单工厂 模式到 工厂方法 模式,再到 抽象工厂 模式。工厂名称含义是制造产品的工业场所,应用在面向对象中,顺理成章地成为了比较典型的创建型模式

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!