[b]介绍[/b]
享元模式(Flyweight),运行共享技术有效地支持大量细粒度的对象,避免大量拥有相同内容的小类的开销(如耗费内存),使大家共享一个类(元类)。
享元模式可以避免大量非常相似类的开销,在程序设计中,有时需要生产大量细粒度的类实例来表示数据,如果能发现这些实例除了几个参数以外,开销基本相同的 话,就可以大幅度较少需要实例化的类的数量。如果能把那些参数移动到类实例的外面,在方法调用的时候将他们传递进来,就可以通过共享大幅度第减少单个实例 的数目。
那么如果在JavaScript中应用享元模式呢?有两种方式,第一种是应用在数据层上,主要是应用在内存里大量相似的对象上;第二种是应用在DOM层上,享元可以用在中央事件管理器上用来避免给父容器里的每个子元素都附加事件句柄。
[b]享元与数据层[/b]
Flyweight中有两个重要概念--内部状态intrinsic和外部状态extrinsic之分,内部状态就是在对象里通过内部方法管理,而外部信息可以在通过外部删除或者保存。
说白点,就是先捏一个的原始模型,然后随着不同场合和环境,再产生各具特征的具体模型,很显然,在这里需要产生不同的新对象,所以Flyweight模式中常出现Factory模式,Flyweight的内部状态是用来共享的,Flyweight factory负责维护一个Flyweight pool(模式池)来存放内部状态的对象。
[b]使用享元模式[/b]
让我们来演示一下如果通过一个类库让系统来管理所有的书籍,每个书籍的元数据暂定为如下内容:
[url=#]
<span class="info">
这里是更多信息
</span></div>
<div class="toggle" href="#">更多信息 (地图)
<span class="info">
<iframe src="http://www.map-generator.net/extmap.php?name=London&address=london%2C%20england&width=500...gt;"</iframe>
</span>
</div>
</div>
JavaScript:
stateManager = {
fly: function(){
var self = this;
$('#container').unbind().bind("click", function(e){
var target = $(e.originalTarget || e.srcElement);
// 判断是哪一个子元素
if(target.is("div.toggle")){
self.handleClick(target);
}
});
},
handleClick: function(elem){
elem.find('span').toggle('slow');
}
});
例2:应用享元模式提升性能
另外一个例子,依然和jQuery有关,一般我们在事件的回调函数里使用元素对象是会后,经常会用到$(this)这种形式,其实它重复创建了新对象,因为本身回调函数里的this已经是DOM元素自身了,我们必要必要使用如下这样的代码:
$('div').bind('click', function(){
console.log('You clicked: ' + $(this).attr('id'));
});
// 上面的代码,要避免使用,避免再次对DOM元素进行生成jQuery对象,因为这里可以直接使用DOM元素自身了。
$('div').bind('click', function(){
console.log('You clicked: ' + this.id);
});
其实,如果非要用$(this)这样的形式,我们也可以实现自己版本的单实例模式,比如我们来实现一个jQuery.signle(this)这样的函数以便返回DOM元素自身:
jQuery.single = (function(o){
var collection = jQuery([1]);
return function(element) {
// 将元素放到集合里
collection[0] = element;
// 返回集合
return collection;
};
});
使用方法:
$('div').bind('click', function(){
var html = jQuery.single(this).next().html();
console.log(html);
});
这样,就是原样返回DOM元素自身了,而且不进行jQuery对象的创建。
[b]总结[/b]
Flyweight模式是一个提高程序效率和性能的模式,会大大加快程序的运行速度.应用场合很多:比如你要从一个数据库中读取一系列字符串,这些字符串中有许多是重复的,那么我们可以将这些字符串储存在Flyweight池(pool)中。
如果一个应用程序使用了大量的对象,而这些大量的对象造成了很大的存储开心时就应该考虑使用享元模式;还有就是对象的大多数状态可以外部状态,如果删除对象的外部状态,那么就可以用相对较少的共享对象取代很多组对象,此时可以考虑使用享元模式。