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

基本知识

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

享元模式的实现和应用

一般实现

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

 function Iphone(model, screen, memory, SN) {
this. model = model;
this.screen = screen;
this.memory = memory;
this.SN = SN;
}
var phones = [];
for (var i = 0; i < 1000000; i++) {
var memory = i % 2 == 0 ? 16 : 32;
phones.push(new Iphone("iphone6s", 5.0, memory, i));
}

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

 function IphoneFlyweight(model, screen, memory) {
this.model = model;
this.screen = screen;
this.memory = memory;
}

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

 var flyweightFactory = (function () {
var iphones = {};
return {
get: function (model, screen, memory) {
var key = model + screen + memory;
if (!iphones[key]) {
iphones[key] = new IphoneFlyweight(model, screen, memory);
}
return iphones[key];
}
};
})();

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

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

然后我们依旧像之间那样生成多个iphone

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

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

享元模式在DOM中的应用

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

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

点击菜单项,进行相应的操作,我们通过jQuery来绑定事件,一般会这么做:

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

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

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

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

总结

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

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

Javascript设计模式理论与实战:享元模式的更多相关文章

  1. Javascript设计模式理论与实战:桥接模式

    桥接模式将抽象部分与实现部分分离开来,使两者都可以独立的变化,并且可以一起和谐地工作.抽象部分和实现部分都可以独立的变化而不会互相影响,降低了代码的耦合性,提高了代码的扩展性. 基本理论 桥接模式定义 ...

  2. Javascript设计模式理论与实战:状态模式

    在软件开发中,很大部分时候就是操作数据,而不同数据下展示的结果我们将其抽象出来称为状态,我们平时开发时本质上就是对应用程序的各种状态进行切换并作出相应处理.状态模式就是一种适合多种状态场景下的设计模式 ...

  3. Javascript设计模式理论与实战:组合模式

    我们平时开发过程中,一定会遇到这种情况:同时处理简单对象和由简单对象组成的复杂对象,这些简单对象和复杂对象会组合成树形结构,在客户端对其处理的时候要保持一致性.比如电商网站中的产品订单,每一张产品订单 ...

  4. 前端读者 | Javascript设计模式理论与实战:状态模式

    本文来自 @狼狼的蓝胖子:链接:http://luopq.com/2015/11/25/design-pattern-state/ 在软件开发中,很大部分时候就是操作数据,而不同数据下展示的结果我们将 ...

  5. Javascript设计模式理论与实战:工厂方法模式

    本文从简单工厂模式的缺点说起,引入工厂方法模式,介绍的工厂方法模式的基本知识,实现要点和应用场景,最后举例进行说明工厂方法模式的应用.在之前的<Javascript设计模式理论与实战:简单工厂模 ...

  6. Java设计模式(十一) 享元模式

    原创文章,同步发自作者个人博客 http://www.jasongj.com/design_pattern/flyweight/.转载请注明出处 享元模式介绍 享元模式适用场景 面向对象技术可以很好的 ...

  7. 设计模式(十)享元模式Flyweight(结构型)

    设计模式(十)享元模式Flyweight(结构型) 说明: 相对于其它模式,Flyweight模式在PHP实现似乎没有太大的意义,因为PHP的生命周期就在一个请求,请求执行完了,php占用的资源都被释 ...

  8. 重学 Java 设计模式:实战享元模式「基于Redis秒杀,提供活动与库存信息查询场景」

    作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 程序员‍‍的上下文是什么? 很多时候一大部分编程开发的人员都只是关注于功能的实现,只 ...

  9. js设计模式(8)---享元模式

    0.前言 今天总结了四种设计模式,到现在有点精疲力尽了,但是还是有不少收获,很开心自己有掌握了新的东西,今天变得有了价值. 1.使用条件 1.1.网页中使用了大量资源密集型的对象: 1.2.这些对象中 ...

随机推荐

  1. 项目中调试SQLServer 方便的查看SQL语句的执行时间的方法

    第一种方法,先记录执行前的时间,然后在记录执行Sql后的时间,然后做减法 1 第一种方法: 2 declare @begin_date datetime 3 declare @end_date dat ...

  2. [leetcode]367. Valid Perfect Square验证完全平方数

    Given a positive integer num, write a function which returns True if num is a perfect square else Fa ...

  3. Linux CentOS6.6 NFS服务的配置与安装

    一.简介 NFS(Network File System)即网络文件系统,是FreeBSD支持的文件系统中的一种,它允许网络中的计算机之间通过TCP/IP网络共享资源.在NFS的应用中,本地NFS的客 ...

  4. mysql中GROUP_CONCAT的使用

    现在有三个表,结构如下: cate表 CREATE TABLE `cate` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'id', ...

  5. 【SQL模板】一.修改/新增存储过程TSQL

    ---Name: 创建存储过程模板.sql ---Purpose: 用于创建 数据库中 新的存储过程 ---Author: xx ---Time: 2015-12-18 10:26:06 ---Rem ...

  6. .NET资源文件实现多语言切换

    1.创建对应的资源文件 lang.en.resx  英文 lang.resx   中文,默认 lang.zh-tw.resx  繁体 首先说明,这三个文件前面部分名称需要一样,只是 点 后面的语言代号 ...

  7. mvc下ajax请求遇到session超时简单处理方式

    转自:http://blog.csdn.net/yeyicsdn/article/details/50032787 参考网址:http://www.cnblogs.com/RachelChen/p/5 ...

  8. Judy Array API介绍

    本文介绍https://code.google.com/p/judyarray/这个JudyArray实现的API. judy_open:新建一个JudyArray,并返回指向这个JudyArray的 ...

  9. Scrum 项目1.0--软件工程

    1.确定选题 视频:http://v.youku.com/v_show/id_XMTU1OTExOTY2NA==.html 2.需求分析调查 地址:http://www.sojump.com/m/81 ...

  10. geoserver 源码介绍

    上一章我们通过实现一个服务对如何扩展GeoServer有了一定的了解,但是,对于为何要这样做并没有说明,本章我们重点来说说GeoServer的结构,下图来自GeoServer官网(希望没有侵权),它很 ...