定义

享元模式要求将对象的属性划分为内部状态和外部状态(状态在这里通常指属性),其目标是尽量减少共享对象的数量

理解

  1. 享元模式通过共享大量的细粒度的对象,减少对象的数量,从而减少对象的内存,提高应用程序的性能。其基本思想就是分解现有类似对象的组成,将其展开为可以共享的内在数据和不可共享的外在数据,我们称内在数据的对象为享元对象。通常还需要一个工厂类来维护内在数据。<br />
  • Flyweight 是抽象享元角色,为具体享元角色规定了必须实现的方法。
  • ConcreteFlyweight 是具体享元角色,实现抽象享元角色定义的方法。
  • FlyweightFactory 是享元工厂,负责创建和管理享元角色,它用于构造一个池容器,同时提供从池中获得对象的方法。
  • Client 是客户端角色:维护对所有享元对象的引用,而且还需要存储对应的外蕴状态。

    demo

    享元前

    有个服装厂,生产了男女服装各50种款式,为了推销需要找模特来拍照,正常可能会找男女模特各50个,每个模特分别穿一种服装拍一组照片。其代码实现如下:
    1. // 模特类
    2. class Modal {
    3. constructor(name, gender, clothes) {
    4. this.name = name
    5. this.gender = gender
    6. this.clothes = clothes
    7. }
    8. takePhoto() {
    9. console.log(`${this.gender}模特${this.name}穿${this.clothes}拍了张照`)
    10. }
    11. }
    12. // 穿衣拍照实现
    13. for (let i = 0; i < 50; i++) {
    14. let manModel = new Modal(`张${i}`, '男', `服装${i}`)
    15. manModel.takePhoto()
    16. }
    17. for (let i = 50; i < 100; i++) {
    18. let womanModel = new Modal(`李${i}`, '女', `服装${i}`)
    19. womanModel.takePhoto()
    20. }

享元后

分析

此时享元模式可以帮助我们来解决这个问题,仔细分析一下,其实不管有多少种类衣服,我们只需要男女各一个模特来穿衣服进行拍照也可实现该需求,实现享元模式的核心就是学会划分内部状态和外部状态,下面几条经验可以供我们快速对内部外部状态进行划分

  • 内部状态存储于对象的内部
  • 内部状态可以被一些对象共享
  • 内部状态独立于具体的场景,通常不会改变
  • 外部状态取决于具体的场景,并根据场景而变化,外部状态不能被共享

    通过上面的方法进行分析后可以得出对于模特对象来说性别是其内部状态,而衣服是外部状态,下面我们使用享元模式来对这个例子进行改造

    实现

    构建享元对象

    1. class Modal {
    2. constructor(id, gender) {
    3. this.gender = gender
    4. this.name = `张${gender}${id}`
    5. }
    6. }

    构建享元工厂

    1. class ModalFactory {
    2. //单例模式
    3. static create(id, gender) {
    4. if (this[gender]) {
    5. return this[gender]
    6. }
    7. return this[gender] = new Modal(id, gender)
    8. }
    9. }

    管理外部状态

    1. class TakeClothesManager {
    2. // 添加衣服款式
    3. static addClothes(id, gender, clothes) {
    4. const modal = ModalFactory.create(id, gender)
    5. this[id] = {
    6. clothes,
    7. modal
    8. }
    9. }
    10. // 拍照
    11. static takePhoto(id) {
    12. const obj = this[id]
    13. console.log(`${obj.modal.gender}模特${obj.modal.name}穿${obj.clothes}拍了张照`)
    14. }
    15. }

    构建享元工厂 ``javascript for (let i = 0; i < 50; i++) { TakeClothesManager.addClothes(i, '男',服装${i}`) TakeClothesManager.takePhoto(i) }

for (let i = 50; i < 100; i++) { const {addClothes, takePhoto} = TakeClothesManager TakeClothesManager.addClothes(i, ‘女’, 服装${i}) TakeClothesManager.takePhoto(i) } ```

总结

  • 享元模式可以简单的理解为 单例模式 + 工厂模式 + 管理器 , 管理器对外部状态进行管理组合成完整的对象
  • 享元模式是一种很好的性能优化方案,但它也会带来一些复杂性的问题,从上面的例子可以看到,使用了享元模式之后,我们需要分别多维护一个 factory 对象和一个 manager 对 象,在大部分不必要使用享元模式的环境下,这些开销是可以避免的。
  • 享元模式带来的好处很大程度上取决于如何使用以及何时使用,一般来说,以下情况发生时 便可以使用享元模式:
    • 对象的大多数状态都可以变为外部状态
    • 一个程序中使用了大量的相似对象
    • 由于使用了大量对象,造成很大的内存开销
    • 剥离出对象的外部状态之后,可以用相对较少的共享对象取代大量对象