Javascript设计模式理论与实战:享元模式

 

享元模式不一样于通常的设计模式,它主要用来优化程序的性能,它最适合解决大量相似的对象而产生的性能问题。享元模式经过分析应用程序的对象,将其解析为内在数据和外在数据,减小对象的数量,从而提升应用程序的性能。设计模式

基本知识

享元模式经过共享大量的细粒度的对象,减小对象的数量,从而减小对象的内存,提升应用程序的性能。其基本思想就是分解现有相似对象的组成,将其展开为能够共享的内在数据和不可共享的外在数据,咱们称内在数据的对象为享元对象。一般还须要一个工厂类来维护内在数据。
在JS中,享元模式主要有下面几个角色组成:
(1)客户端:用来调用享元工厂来获取内在数据的类,一般是应用程序所需的对象,
(2)享元工厂:用来维护享元数据的类
(3)享元类:保持内在数据的类iphone

享元模式的实现和应用

通常实现

咱们举个例子进行说明:苹果公司批量生产iphone,iphone的大部分数据好比型号,屏幕都是同样,少数部分数据好比内存有分16G,32G等。未使用享元模式前,咱们写代码以下:函数

 1 function Iphone(model, screen, memory, SN) {
 2     this. model  = model;
 3     this.screen = screen;
 4     this.memory = memory;
 5     this.SN = SN;
 6 }
 7 var phones = [];
 8 for (var i = 0; i < 1000000; i++) {
 9     var memory = i % 2 == 0 ? 16 : 32;
10     phones.push(new Iphone("iphone6s", 5.0, memory, i));
11 }

这段代码中,建立了一百万个iphone,每一个iphone都独立申请一个内存。可是咱们仔细观察能够看到,大部分iphone都是相似的,只是内存和序列号不同,若是是一个对性能要求比较高的程序,咱们就要考虑去优化它。
大量类似对象的程序,咱们就能够考虑用享元模式去优化它,咱们分析出大部分的iphone的型号,屏幕,内存都是同样的,那这部分数据就能够公用,就是享元模式中的内在数据,定义享元类以下:性能

1 function IphoneFlyweight(model, screen, memory) {
2     this.model = model;
3     this.screen = screen;
4     this.memory = memory;
5 }

咱们定义了iphone的享元类,其中包含型号,屏幕和内存三个数据。咱们还须要一个享元工厂来维护这些数据:优化

 1 var flyweightFactory = (function () {
 2     var iphones = {};
 3     return {
 4         get: function (model, screen, memory) {
 5             var key = model + screen + memory;
 6             if (!iphones[key]) {
 7                 iphones[key] = new IphoneFlyweight(model, screen, memory);
 8             }
 9             return iphones[key];
10         }
11     };
12 })();

在这个工厂中,咱们定义了一个字典来保存享元对象,提供一个方法根据参数来获取享元对象,若是字典中有则直接返回,没有则建立一个返回。
接着咱们建立一个客户端类,这个客户端类就是修改自iphone类:this

1 function Iphone(model, screen, memory, SN) {
2     this.flyweight = flyweightFactory.get(model, screen, memory);
3     this.SN = SN;
4 }

而后咱们依旧像之间那样生成多个iphonespa

1 var phones = [];
2 for (var i = 0; i < 1000000; i++) {
3     var memory = i % 2 == 0 ? 16 : 32;
4     phones.push(new Iphone("iphone6s", 5.0, memory, i));
5 }
6 console.log(phones);

这里的关键就在于Iphone构造函数里面的this.flyweight = flyweightFactory.get(model, screen, memory)。这句代码经过享元工厂去获取享元数据,而在享元工厂里面,若是已经存在相同数据的对象则会直接返回对象,多个iphone对象共享这部分相同的数据,因此本来相似的数据已经大大减小,减小的内存的占用。设计

享元模式在DOM中的应用

享元模式的一个典型应用就是DOM事件操做,DOM事件机制分红事件冒泡和事件捕获。咱们简单介绍一下这二者:
事件冒泡:绑定的事件从最里层的元素开始触发,而后冒泡到最外层
事件捕获:绑定的事件从最外层的元素开始触发,而后传到最里层
假设咱们HTML中有一个菜单列表code

1 <ul class="menu">
2     <li class="item">选项1</li>
3     <li class="item">选项2</li>
4     <li class="item">选项3</li>
5     <li class="item">选项4</li>
6     <li class="item">选项5</li>
7     <li class="item">选项6</li>
8 </ul>

点击菜单项,进行相应的操做,咱们经过jQuery来绑定事件,通常会这么作:对象

1 $(".item").on("click", function () {
2     console.log($(this).text());
3 })

给每一个列表项绑定事件,点击输出相应的文本。这样看暂时没有什么问题,可是若是是一个很长的列表,尤为是在移动端特别长的列表时,就会有性能问题,由于每一个项都绑定了事件,都占用了内存。可是这些事件处理程序其实都是很相似的,咱们就要对其优化。

1 $(".menu").on("click", ".item", function () {
2     console.log($(this).text());
3 })

经过这种方式进行事件绑定,能够减小事件处理程序的数量,这种方式叫作事件委托,也是运用了享元模式的原理。事件处理程序是公用的内在部分,每一个菜单项各自的文本就是外在部分。咱们简单说下事件委托的原理:点击菜单项,事件会从li元素冒泡到ul元素,咱们绑定事件到ul上,实际上就绑定了一个事件,而后经过事件参数event里面的target来判断点击的具体是哪个元素,好比低级第一个li元素,event.target就是li,这样就能拿到具体的点击元素了,就能够根据不一样元素进行不一样的处理。

总结

享元模式是一种优化程序性能的手段,经过共享公用数据来减小对象数量以达到优化程序的手段。享元模式适用于拥有大量相似对象而且对性能有要求的场景。由于享元模式须要分离内部和外部数据,增长了程序的逻辑复杂性,建议对性能有要求的时候才使用享元模式。

原文地址:http://luopq.com/2015/11/20/design-pattern-flyweight/

相关文章
相关标签/搜索