【设计模式】享元模式(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有自己的内存回收机制,这个可选。

版权所有,转载请注明出处:

http://www.cnblogs.com/sickworm/p/4016026.html

时间: 2024-10-14 21:04:42

【设计模式】享元模式(Flyweight)的相关文章

深入浅出设计模式——享元模式(Flyweight Pattern)

模式动机 面向对象技术可以很好地解决一些灵活性或可扩展性问题,但在很多情况下需要在系统中增加类和对象的个数.当对象数量太多时,将导致运行代价过高,带来性能下降等问题.享元模式正是为解决这一类问题而诞生的.享元模式通过共享技术实现相同或相似对象的重用. 在享元模式中可以共享的相同内容称为内部状态(Intrinsic State),而那些需要外部环境来设置的不能共享的内容称为外部状态(Extrinsic State),由于区分了内部状态和外部状态,因此可以通过设置不同的外部状态使得相同的对象可以具有

二十四种设计模式:享元模式(Flyweight Pattern)

享元模式(Flyweight Pattern) 介绍运用共享技术有效地支持大量细粒度的对象. 示例有一个Message实体类,某些对象对它的操作有Insert()和Get()方法,现在要运用共享技术支持这些对象. MessageModel using System; using System.Collections.Generic; using System.Text; namespace Pattern.Flyweight { /// <summary> /// Message实体类 ///

设计模式——享元模式

Flyweight 直译为蝇量.就其表示的模式来说,翻译成享元,确实是不错的 package designpattern.structure.flyweight; public interface Flyweight { void action(int arg); } package designpattern.structure.flyweight; public class FlyweightImpl implements Flyweight { public void action(int

8. 星际争霸之php设计模式--享元模式

题记==============================================================================本php设计模式专辑来源于博客(jymoz.com),现在已经访问不了了,这一系列文章是我找了很久才找到完整的,感谢作者jymoz的辛苦付出哦! 本文地址:http://www.cnblogs.com/davidhhuan/p/4248186.html============================================

java设计模式--享元模式

享元模式(flyweight) 当需要有很多完全相同或相似的对象需要创建的时候,主要是相似的时候,我们可以用享元模式.尽可能少创建对象,节省内存. 享元模式主要有4中角色 1.享元的工厂 2.抽象享元对象 2.内部状态对象:可以共享的 3.外部状态对象:不可以共享的 下面以围棋的棋子为例:每个棋子都是一个对象,但是每个棋子的大部分都一样,只有颜色,摆放位置不一样,这样就没必要每个棋子都创建一个对象,把相同的和不同的分离开来. //享元类抽象 public interface FlyWeight

享元模式Flyweight

享元模式 享元模式Flyweight,布布扣,bubuko.com

设计模式之禅之设计模式-享元模式

一:享元模式定义        --->享元模式(Flyweight Pattern)是池技术的重要实现方式        --->使用共享对象可有效地支持大量的细粒度的对象        --->要求细粒度对象,那么不可避免地使得对象数量多且性质相近,那我们就将些对象的信息分为两个部分:内部状态(intrinsic)与外部状态(extrinsic).                ● 内部状态                        内部状态是对象可共享出来的信息,存储在享元对象

享元模式-Flyweight(Java实现)

享元模式-Flyweight 享元模式的主要目的是实现对象的共享,即共享池,当系统中对象多的时候可以减少内存的开销,通常与工厂模式一起使用. 本文中的例子如下: 使用享元模式: 小明想看编程技术的书, 就到家里的书架上拿, 如果有就直接看, 没有就去买一本, 回家看. 看完了就放到家里的书架上, 以后再想看了直接就在书架上拿, 不需要再去买同样的这本书了. 不适用享元模式: 小明想看编程技术的书, 就去书店里买一本回家看, 买完后看完了, 书就不知道丢到了哪里去了. 下次想看的时候就找不到了,

[工作中的设计模式]享元模式模式FlyWeight

一.模式解析 Flyweight在拳击比赛中指最轻量级,即“蝇量级”或“雨量级”,这里选择使用“享元模式”的意译,是因为这样更能反映模式的用意.享元模式是对象的结构模式.享元模式以共享的方式高效地支持大量的细粒度对象. 享元模式:主要为了在创建对象时,对共有对象以缓存的方式进行保存,对外部对象进行单独创建 模式要点: 1.享元模式中的对象分为两部分:共性部分和个性化部分,共性部分就是每个对象都一致的或者多个对象可以共享的部分,个性化部分指差异比较大,每个类均不同的部分 2.共性部分的抽象就是此模

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

说明: 相对于其它模式,Flyweight模式在PHP实现似乎没有太大的意义,因为PHP的生命周期就在一个请求,请求执行完了,php占用的资源都被释放.我们只是为了学习而简单做了介绍. 1. 概述 面向对象技术可以很好地解决系统一些灵活性或可扩展性或抽象性的问题,但在很多情况下需要在系统中增加类和对象的个数.当对象数量太多时,将导致运行代价过高,带来性能下降等问题.比如:例子1:图形应用中的图元等对象.字处理应用中的字符对象等. 2.解决方案: 享元模式(Flyweight):对象结构型模式运用