《JavaScript设计模式》读书笔记:Flyweight模式

Flyweight模式是一种结构型设计模式,它主要解决的问题是:由于(同类)对象的数量太大,采用面向对象技术时给系统带来了难以承受的内存开销。

拿前端页面常用的tooltip来说。

未使用享元模式的代码

var Tooltip = function(targetElement, text) {
  this.target = targetElement;
  this.text = text;
  this.delayTimeout = null;
  this.delay = 1500; // in milliseconds.
  // Create the HTML.
  this.element = document.createElement('div');
  this.element.style.display = 'none';  
  this.element.style.position = 'absolute';    
  this.element.className = 'tooltip';
  document.getElementsByTagName('body')[0].appendChild(this.element);
  this.element.innerHTML = this.text;
  // Attach the events.
  var that = this; // Correcting the scope.
  addEvent(this.target, 'mouseover', function(e) { that.startDelay(e); });
  addEvent(this.target, 'mouseout', function(e) { that.hide(); });  
};
Tooltip.prototype = {
  startDelay: function(e) {
    if(this.delayTimeout == null) {
      var that = this;
      var x = e.clientX;
      var y = e.clientY;
      this.delayTimeout = setTimeout(function() { 
        that.show(x, y); 
      }, this.delay);
    }
  },
  show: function(x, y) {
    clearTimeout(this.delayTimeout);
    this.delayTimeout = null;
    this.element.style.left = (x) + 'px';    
    this.element.style.top = (y + 20) + 'px';
    this.element.style.display = 'block';    
  },
  hide: function() {
    clearTimeout(this.delayTimeout);
    this.delayTimeout = null;
    this.element.style.display = 'none';
  }
};

这是Tooltip类的定义。在前端这样使用:

var linkElement = $('link-id');
var tt = new Tooltip(linkElement, 'Lorem ipsum...');
这样使用有一个很大的弊端就是:在前端页面上,可能有许许多多成百上千的元素需要用到tooltip。
如果为这些元素每个都生成一个Tooltip对象,那将极大的浪费内存,效率也非常低下。
这时就可以使用享元模式来改造这个类,代码如下:
/* Tooltip class, as a flyweight. */
var Tooltip = function() {
  this.delayTimeout = null;
  this.delay = 1500; // in milliseconds.
  // Create the HTML.
  this.element = document.createElement('div');
  this.element.style.display = 'none';  
  this.element.style.position = 'absolute';    
  this.element.className = 'tooltip';
  document.getElementsByTagName('body')[0].appendChild(this.element);
};
Tooltip.prototype = {
  startDelay: function(e, text) {
    if(this.delayTimeout == null) {
      var that = this;
      var x = e.clientX;
      var y = e.clientY;
      this.delayTimeout = setTimeout(function() { 
        that.show(x, y, text); 
      }, this.delay);
    }
  },
  show: function(x, y, text) {
    clearTimeout(this.delayTimeout);
    this.delayTimeout = null;
    this.element.innerHTML = text;
    this.element.style.left = (x) + 'px';    
    this.element.style.top = (y + 20) + 'px';
    this.element.style.display = 'block';    
  },
  hide: function() {
    clearTimeout(this.delayTimeout);
    this.delayTimeout = null;
    this.element.style.display = 'none';
  }
};
/* TooltipManager singleton, a flyweight factory and manager. */
var TooltipManager = (function() {
  var storedInstance = null;
  
  /* Tooltip class, as a flyweight. */
  var Tooltip = function() {
    ...
  };
 Tooltip.prototype = {
   ...
  };
  return {
    addTooltip: function(targetElement, text) {
      // Get the tooltip object.
      var tt = this.getTooltip();
      
      // Attach the events.
      addEvent(targetElement, 'mouseover', function(e) { tt.startDelay(e, text); });
      addEvent(targetElement, 'mouseout', function(e) { tt.hide(); });      
    },
    getTooltip: function() {
      if(storedInstance == null) {
        storedInstance = new Tooltip();
      }
      return storedInstance;
    }
  };
})();
改造后的Tooltip类在前段这样使用:
TooltipManager.addTooltip($('link-id'), 'Lorem ipsum...');
 
用享用模式改造后的类相比以前的类有了一些改进。
它创建了一个闭包,将Tooltip类和集Tooltip对象管理和Tooltip工厂方法于一体的TooltipManager类放置其中,并返回一个singleton。
将tooltip的触发元素targetElement和文本text从Tooltip类的构造函数中取出,并将它们作为参数传入sinleton里的addTooltip方法中。
在使用这个新的Tooltip类时,我们只需要用TooltipManager类中的addTooltip方法即可。
TooltipManager中的getTooltip方法保证了全局中只有一个Tooltip实例。大大减少了对象数量,节省了内存空间。
原文地址:https://www.cnblogs.com/followflows/p/1706366.html