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实例。大大减少了对象数量,节省了内存空间。