【设计模式】享元模式(Flyweight)
摘要:
1.本文将详细介绍享元模式的原理和实际代码中特别是Android系统代码中的应用。
纲要:
1. 引入享元模式
2. 享元模式的概念及优缺点介绍
3. 享元模式在Android源码中的应用
1.先来一个段子:
GG每天给MM至少发一条短信,而且每天入睡前是必有一条短信的,往往是一些琐事和一些比较肉麻的情话。开始的一个月,GG还对此是乐不可支,随着时间的推移,那些肉麻的话说了很多遍,自己也觉得厌烦了,而且更让人不可忍耐的是这些肉麻的情话每次都要重复的输入。GG把这一烦心事告诉了自己的好友K,K说,“你这个大傻瓜,怎么不把一些你常用的话存放在你的手机中,这样,要用的时候,直接拿来用就行了”,傻GG一听,顿时觉得醍醐灌顶,于是立即在手机中存放入了“宝贝儿,晚安喔”、“你是我天使”,“宝贝儿,我永远的爱你”等话语。(摘自Android大话设计模式)
2.享元模式介绍
2.1什么是享元模式?
为了节约内存资源,把具有重复性质的实例进行统一管理(结合Factory模式),使用时对象一般不创建新实例,只进行引用。Flyweight本是体育上的一个术语,用来表示轻量级。Flyweight,飞翔般的重量,说明使用它会使代码变得“轻”(指内存消耗方面)起来。
2.2享元模式有什么好处?
上面已经提到了,它最大也是唯一的好处就是:“轻”。享元能够节省重复实例的内存消耗。举两个最经典的例子。
1、26个英文字母的点阵显示数据。我们使用它们的时候,如果每次使用都创建新的字母实例,那内存浪费是很严重的。我们可以很容易的想到,将这26个点阵数据个创建一个实例,并专门用一个类管理起来。当用户需要使用的时候,给他们这些实例的引用,这样就能大大节省内存消耗了。
2、画画。假设我能画的图形是有限的(圆,长方形,棱形,梯形等),画画就是把这些图形不断的往上贴图。当我一幅画有上千个图案的时候,享元模式就成为了很好的减少内存消耗的解决方案。我们把固定的图形都只创建一个实例,等要画的时候,使用它们的引用“作画”即可。
不过这个画画的例子就有问题了:这些独立图形的位置,大小,颜色都不一样,而实例只有一个,这样画出来岂不是都挤一块去了?这里是享元模式的关键的地方:区分内蕴态和外蕴态。简单说就是:一部分(图形)共享(称为内部储存或内部状态),一部分(大小,位置,颜色)不公享(称为外部储存或外部状态)。把这个概念加进去,享元模式就灵活多了。
3.源码实战:
3.1String:
没想到吧!String用到了享元模式。其实我也没想到。就我个人理解,与其说String使用享元模式,不如说是用到了它的思想,毕竟它的实现不是通过活生生的Java代码。下面一起来看一下:
String s0=”abc”; String s1=”abc”; String s2=”a” + “bc”; System.out.println( s0==s1 ); System.out.println( s0==s2 );
结果为:
true true
我们都知道,String是一种对象(非基础类型,下同),对象的==比较的是和指向的内存有关的。如果两个对象指向的是同一个数据,那他们是相等的(Java语言是不支持重载的,所以没有例外情况)。
但上面的写法不应该是三个独立的数据段吗?这里就涉及到常量池。
常量池(constant pool)指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口等中的常量,也包括字符串常量。 这些字符串对于编译器来说,都是同样的常量字符串,所以编译器把他们简化成了一条数据,从而优化了内存使用。这和享元模式的思想如出一辙。
如果我们这样写:
String s0=”abc”; String s1= new String(“abc”); System.out.println( s0==s1 );
结果为:
false
为什么会这样?因为s1等号右边不是常量字符串,而是实例化操作,人家编译器不认这种非静态的东西。这也说明了一点,享元需要专门的类来管理,否则就会出现上面那种不适用的情况。一般来说都是用Factory。
3.2SQLiteCompiledSql:
(参考Android设计模式系列(6)--SDK源码之享元模式 http://www.cnblogs.com/qianxudetianxia/archive/2011/08/10/2133659.html)
Android中SQLiteCompiledSql的使用,其实是很多数据库系统典型的实现。从应用启动,通过各种数据库操作,我们不知道进行了多少次的查询操作,而这些操作中又有相当一部分sql语句是相同的,这些编译后的sql编译对象其实是一样的,是可以共用共享的,其实就是缓存。SQLiteCompiledSql就是这样的一个需要共享的享元对象。
UML图:
其中SQLiteCompiledSql就是被管理享元对象,主要是内部状态sql语句:
class SQLiteCompiledSql { private String mSqlStmt = null; native_compile(sql); native_finalize(); }
享元对象只是存放固定内容的实例,具体实现精华在管理享元对象的工厂中。
SqliteDatabase就是管理享元对象的工厂,它里面的mCompiledQuerie就是存放享元对象的容器。通常都是使用HashMap(HashTable的替代品,详细http://oznyang.iteye.com/blog/30690)进行储存。通过这种方式大大减少了sql编译对象的创建,提高了数据库操作的性能。
public class SQLiteDatabase{ Map<String, SQLiteCompiledSql> mCompiledQueries = Maps.newHashMap(); SQLiteCompiledSql getCompiledStatementForSql(String sql) { SQLiteCompiledSql compiledStatement = null; boolean cacheHit; synchronized(mCompiledQueries) { if (mMaxSqlCacheSize == 0) { return null; } cacheHit = (compiledStatement = mCompiledQueries.get(sql)) != null; } if (cacheHit) { mNumCacheHits++; } else { mNumCacheMisses++; } return compiledStatement; } private void deallocCachedSqlStatements() { synchronized (mCompiledQueries) { for (SQLiteCompiledSql compiledSql : mCompiledQueries.values()) { compiledSql.releaseSqlStatement(); } mCompiledQueries.clear(); } } void addToCompiledQueries(String sql, SQLiteCompiledSql compiledStatement) { //省略具体代码 } }
大体享元工厂都是这样一个结构:
HashMap:用作储存(就和String的常量池一样)
get方法:得到享元对象的引用
add方法:增加新的享元对象,用作初始化,一般使用者不会接触到。也有更灵活的享元模式使用会动态的增加HashMap没有的享元对象(设计模式是死的,人写出来的代码是活的,怎么用全凭大家)。
dealloc方法:释放所有的享元对象,Java有自己的内存回收机制,这个可选。
版权所有,转载请注明出处:
【设计模式】享元模式(Flyweight)的更多相关文章
- 设计模式-享元模式(FlyWeight)
一.概念 享元模式是对象的结构模式,它以共享的方式高效的支持大量的细粒度对象,减少对象的数量,并达到节约内存的目的. 享元对象能够做到共享的关键,主要是区分了内部状态和外部状态,内部状态是对象是在建立 ...
- 设计模式--享元模式Flyweight(结构型)
一.享元模式 在一个系统中如果有多个相同的对象,这些对象有部分状态是可以共享的,我们运用共享技术就能有效地支持大量细粒度的对象. 二.例子 举个围棋的例子,围棋的棋盘共有361格,即可放361个棋子. ...
- 大话设计模式--享元模式 Flyweight -- C++实现实例
1. 享元模式: 运用共享技术有效地支持大量细粒度的对象. 享元模式可以避免大量非常相似类的开销,在程序设计中,有时需要生成大量颗粒度的类实例来表示数据,如果能发现这些实例除了几个参数外基本都是相同的 ...
- 深入浅出设计模式——享元模式(Flyweight Pattern)
模式动机 面向对象技术可以很好地解决一些灵活性或可扩展性问题,但在很多情况下需要在系统中增加类和对象的个数.当对象数量太多时,将导致运行代价过高,带来性能下降等问题.享元模式正是为解决这一类问题而诞生 ...
- 设计模式(十)享元模式Flyweight(结构型)
设计模式(十)享元模式Flyweight(结构型) 说明: 相对于其它模式,Flyweight模式在PHP实现似乎没有太大的意义,因为PHP的生命周期就在一个请求,请求执行完了,php占用的资源都被释 ...
- 乐在其中设计模式(C#) - 享元模式(Flyweight Pattern)
原文:乐在其中设计模式(C#) - 享元模式(Flyweight Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 享元模式(Flyweight Pattern) 作者:weba ...
- 享元模式 FlyWeight 结构型 设计模式(十五)
享元模式(FlyWeight) “享”取“共享”之意,“元”取“单元”之意. 意图 运用共享技术,有效的支持大量细粒度的对象. 意图解析 面向对象的程序设计中,一切皆是对象,这也就意味着系统的运行将 ...
- 设计模式-11享元模式(Flyweight Pattern)
1.模式动机 在面向对象程序设计过程中,有时会面临要创建大量相同或相似对象实例的问题.创建那么多的对象将会耗费很多的系统资源,它是系统性能提高的一个瓶颈. 享元模式就是把相同或相似对象的公共部分提取出 ...
- 设计模式系列之享元模式(Flyweight Pattern)——实现对象的复用
说明:设计模式系列文章是读刘伟所著<设计模式的艺术之道(软件开发人员内功修炼之道)>一书的阅读笔记.个人感觉这本书讲的不错,有兴趣推荐读一读.详细内容也可以看看此书作者的博客https:/ ...
- 【UE4 设计模式】享元模式 Flyweight Pattern
概述 描述 运用共享技术有效地支持大量细粒度对象的复用.系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用. 由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻 ...
随机推荐
- Winform程序部署方式总结二——Windows Installer发布
针对Winform程序,介绍两种常用打包方式:ClickOnce和Windows Installer 应用程序如下: 二.Windows Installer发布 1.新建项目 创建后视图 第一步: 应 ...
- SVG总结小知识
SVG:可缩放矢量图形.全称是:Scalable Vector Graphics SVG使用 XML 格式定义图像. SVG是使用 XML 来描述(二维图形和绘图)程序的语言. SVG是W3C ...
- FreeBSD查看网络情况
FreeBSD查看网络情况 记录一下FreeBSD下常用的统计当前系统网络连接状态的一些命令: 1)统计80端口连接数 netstat -nat|grep -i "80"|wc - ...
- JS变量对象详解
JS变量对象详解 开年之后工作热情一直不是很高,这几天一直处于消极怠工状态.早上不想起床,起床了不想上班.明明放假之前工作热情还一直很高,一直心心念念的想把小程序项目怼出来,结果休假回来之后画风完全不 ...
- Springboot2.x+shiro+redis(Lettuce)整合填坑
主要记录关键和有坑的地方 前提: 1.SpringBoot+shiro已经集成完毕,如果没有集成,先查阅之前的Springboot2.0 集成shiro权限管理 2.redis已经安装完成 3.red ...
- [SOJ #47]集合并卷积
题目大意:给你两个多项式$A,B$,求多项式$C$使得:$$C_n=\sum\limits_{x|y=n}A_xB_y$$题解:$FWT$,他可以解决形如$C_n=\sum\limits_{x\opl ...
- [CQOI2017]老C的方块 网络流
---题面--- 题解: 做这题做了好久,,,换了4种建图QAQ 首先我们观察弃疗的形状,可以发现有一个特点,那就是都以一个固定不变的特殊边为中心的,如果我们将特殊边两边的方块分别称为s块和t块, 那 ...
- POJ.2142 The Balance (拓展欧几里得)
POJ.2142 The Balance (拓展欧几里得) 题意分析 现有2种质量为a克与b克的砝码,求最少 分别用多少个(同时总质量也最小)砝码,使得能称出c克的物品. 设两种砝码分别有x个与y个, ...
- 51nod 1197 字符串的数量 V2(矩阵快速幂+数论?)
接上一篇,那个递推式显然可以用矩阵快速幂优化...自己随便YY了下就出来了,学了一下怎么用LaTeX画公式,LaTeX真是个好东西!嘿嘿嘿 如上图.(刚画错了一发...已更新 然后就可以过V2了 or ...
- Basic Data Structure HDU - 5929 (这个模拟我要报警了)
Mr. Frog learned a basic data structure recently, which is called stack.There are some basic operati ...