JavaScript 设计模式:享元模式原理与实战详解

作者:代码拾荒

时间:2026-10-24

浏览:635

本文深入解析 JavaScript 中的享元模式,阐述其通过分离内部与外部状态来减少细粒度对象创建、降低内存占用的核心原理。文章详细对比了单纯享元与组合享元的区别,并结合 Hashtable 缓存机制与工厂模式,提供了完整的代码实现与运行示例,帮助开发者在实际项目中优化性能。

文章目录

本文详细介绍 JavaScript 中的享元模式,旨在为读者提供参考与学习价值。

享元模式说明

定义:旨在解决系统中大量细粒度对象的共享问题。

核心关键词:分离与共享。

说明:享元模式分为单纯(共享)享元模式和组合(不共享)享元模式,主要区别在于是否共享。单纯享元模式仅包含共享状态,即内部状态,这部分状态是不可变的、不可修改的。同时存在外部状态,它是可变的且不被共享,由客户端负责管理。外部状态与内部状态相互独立,通常作为参数传入享元对象,但不会改变内部状态的值。外部状态常用于获取共享的享元对象,可能与内部状态存在一定关联。例如,从用户数据表中获取数据时,传入一个外部变量(如用户名),再根据该用户名获取该用户的所有对象状态信息。

组合享元模式配置了组合模式,其中共享部分仅作为叶子节点,而组合部分是不必共享的。因为组合部分的子叶节点元素已经被缓存,组合部分主要起到分组分类的作用。

享元模式通常会与工厂模式结合使用,用于管理缓存的创建与维护。享元共享元素的创建通常在工厂类中完成。

享元模式主要用于对象的共享,使具有相似对象或拥有大量相似细粒度状态的对象能够共享已创建的对象,从而减少对象的创建数量,降低内存占用,提升系统性能。

一种场景:

享元模式说明

享元模式结构图:

享元模式说明

如第一张图所示的情况,就可以使用享元模式。因为后两排的状态组合可能在实体对应中多次存在,这时就可以利用享元的共享特性来减少对象的创建。如果有相同的状态或组合,就可以获取缓存的状态,减少对象重复创建,从而减少内存占用。

实例场景:

1. 系统各种角色权限分配;

2. 系统出现很多种状态,或组合状态需要对应的,而且这种对应,可以发生很多种其他类型对象上面的,就可以使用享元模式;

实例源码: 单纯(共享)享元

1. 自定义的 JavaScript Hashtable:


function Hashtable() {
  this.values = [];
}

Hashtable.prototype.getJson = function() {
  return this.values;
}

Hashtable.prototype.add = function(key, value) {
  if (!this.contain(key)) {
    this.values.push({key:key, value:value});
  }
}

Hashtable.prototype.contain = function(key) {
  for (idx in this.values) {
    var json = this.values[idx];
    if (json.key == key) {
      return true;
    }
  }
  return false;
}

Hashtable.prototype.get = function(key) {
  var result;
  for (idx in this.values) {
    var json = this.values[idx];
    if (json.key == key) {
      result = json;
      break;
    }
  }
  return result;
}

Hashtable.prototype.delete = function(key) {
  for (idx in this.values) {
    var json = this.values[idx];
    if (json.key == key) {
      delete this.values[idx];
      break;
    }
  }
}

Hashtable.prototype.set = function(key, value) {
  if (this.contain(key)) {
    this.delete(key);
    this.values.push({key:key,value:value});
  }
}

2. 享元方法:


function Flyweight(one) {
  this.stateOne = one;
}

Flyweight.prototype.operate = function(){
   var date = new Date();
  console.log(this.stateOne + '-' + Math.random());
};

这里可以处理传进来的参数的一些逻辑,也可以初始化从数据库里提取数据缓存保存;

3. 享元工厂:


function FlyweightFactory(){
  var hash = new Hashtable();
}

FlyweightFactory.prototype.getFlyweight = function(state) {
  var flyweight;
  if (hash.contain(state)) {
    flyweight = hash.get(state);
  } else {
    flyweight = new Flyweight(state);
    hash.add(state, flyweight);
  }
  return flyweight;
}

4. Client 使用:


//Client

var factory = new FlyweightFactory();
var fly1, fly2, fly3;

fly1 = factory.getFlyweight('AABB');
fly2 = factory.getFlyweight('CCDD');
fly3 = factory.getFlyweight('CCDD');

fly1.operate();
fly2.operate();
fly3.operate();

输出:

AABB-0.8621504916809499

CCDD-0.7498800195753574

CCDD-0.7498800195753574

复合享元模式

1. 复合享元


function UnShareFlyweight() {
  this.state = '';
  this.hash = new Hashtable();
}

UnShareFlyweight.prototype.add = function(key, flyweight) {
  this.hash.add(key, flyweight);
}

UnShareFlyweight.prototype.operate = function(state) {
  var flag = false;
   /*
  for (idx in this.hash) {
    var fly = this.list[idx];
    if (fly.stateOne == state) {
      flag = true;
       break;
    }
  }
   */
  
   flag = this.hash.contain(state);
  flag ? console.log('Exists') : console.log('Not Exists');
}

2. 在修改添加在享元工厂的组合方法:


function FlyweightFactory(){
  var hash = new Hashtable();
}

FlyweightFactory.prototype.getFlyweight = function(state) {
  var flyweight;
  if (hash.contain(state)) {
    flyweight = hash.get(state);
  } else {
    flyweight = new Flyweight(state);
    hash.add(state, flyweight);
  }
  return flyweight;
}

FlyweightFactory.prototype.getComposite = function(list) {
  var unFly = new UnShareFlyweight();
  var flyweight, state;
  for (idx in list) {
    state = list[idx];
    flyweight = this.getFlyweight(state);
    unFly.add(state, flyweight);
  }
}

FlyweightFactory.prototype.print = function() {
  var jsons = this.hash.getJson();
  for (json in jsons) {
    json.value.operate();
  }
}

3. Client 使用:


var states = ['AABB', 'CDCD', 'AABB', 'CCDD'];

var factory = new FlyweightFactory();
factory.getComposite(states);

factory.print();

输出:

AABB-0.8749617566354573

CDCD-0.6991151459515095

CCDD-0.9891050879377872

享元模式其他说明

总体来说,享元模式用于减少对象的重复创建,用于减少内存使用,提升性能的结构型模式:

它涉及三个模式:享元模式,工厂模式,组合模式;

对于处理多对多对应而产生的一些数据缓存存储,是一个不错的选择!

感兴趣的朋友可以使用在线HTML/CSS/JavaScript代码运行工具:http://tools.jb51.net/code/HtmlJsRun测试上述代码运行效果。

更多关于JavaScript相关内容感兴趣的读者可查看本站专题:《javascript面向对象入门教程》、《JavaScript错误与调试技巧总结》、《JavaScript数据结构与算法技巧总结》、《JavaScript遍历算法与技巧总结》及《JavaScript数学运算用法总结》

希望本文所述对大家JavaScript程序设计有所帮助。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章