设计模式之享元

设计模式之享元模式(flyweight)
何谓享元

首先我们解释一下什么是享元?

这里所说的享元出自大名鼎鼎的设计模式一书,英文flyweight,中文由谁翻译成“享元”一词已不可考,但不得不说,这个翻译实在是精彩;望文即可生意,比起洋鬼子的flyweight高明太多。这不免让我等程序员被洋鬼子压倒在头上多年终于可以聊以自慰(也就是yy),虽然我不如你,但我们的老祖宗可比你们的老祖宗要强多了 我们的老祖宗确实很厉害,搞得我们除了老祖宗的东西也确实没啥能拿出手的,大凡老子是英雄,儿子基本上都是狗熊。这真是悲哀

扯远了,我们继续享元;那何为享元,顾名思义,共享的单元嘛。实例AB都包含指向同一个实例C的索引,而不是直接包含CC就是享元;数据结构描述如下

struct C {

int iIndexOfC;

/* ...*/

}stC;

 

struct A {

    int iIndexOfA;

    struct C *pstFlyWeight;

}stA = {0, &stC};

 

struct B {

    int iIndexOfB;

    struct C *pstFlyWeight;

}stB = {0, &stC};

 

享元的应用

可以说,无论你有没有意识到,代码中享元实际上无处不在。远的不说了,就是设计模式中的举例,文档中文字格式的存储,我们每天都用到,谁不用office软件?如果说这个还是有些遥远,毕竟不是自己设计的部分,那我们再看个例子;如果要存储一个学生信息,包括学号和毕业学校名称,有人会这样设计这个数据结构吗?

struct student {

    unsigned int uiIndex;

    char szCollegeName[32];

};

大部分情况来说,我们都不会这样操作,这确实很浪费存储空间;虽然现在电子产品越来越便宜,但我们也不能这样败家。我们可以这样

struct college {

    unsigned short usCollegeIndex;

    char szCollegeName[32];

};

 

struct student {

    unsigned int uiIndex;

unsigned short uiCollegeIndex;

};

这样效果比较好一些

 

进阶篇

如果享元只是像我举的例子那样简单,享元也就不能称之为享元了;我们再仔细想想文档处理的例子,每个字符包括大小,字体...,理论上应该定义成

struct char_formated {

    char cCharactor;

    short sFont;

char cSize;

struct position stPosition;

/* ... */

};

 

struct file {

    char_formated[x];

};

应用享元模式,定义成这样也就差不多了

struct format_template {

    short sFormatId;

    short sFont;

    char cSize;

    /* ... */

};

 

struct char_formated {

    char cCharactor;

short sForamtId;

struct position stPosition;

};

 

当然,设计模式里面玩的更狠一些,干脆搞成这样

struct formated_char {

short sFormatId;

char cCharactor;

char cSize;

    short sFont;

    /* ... */

};

 

struct char_formated {

    short sForamtId;

struct position stPosition;

};

有人会问这个问题吗?- 从表面上看,存储空间不是耗费更多了吗?至少多了short的空间吧。我看是没有人会问了

所以这才是享元的精髓,把一些私有的信息公共出来,以达到共享的效果;

文档当然是享元的一个完美应用,但平常的代码中有很多的实际的例子,只不过大家没有多想,或者没有在意

举例:公司的应届生招聘信息记录

struct student {

    unsigned int uiIndex;

    unsigned int uiYearEnterCollege;

    unsigned int uiYearGraduate;

    unsigned char ucMonthEnterCollege;

    unsigned char ucMonthGradute;

    unsigned short usCollegeIndex;

    unsigned char ucAge;

    unsigned char ucGender;

    unsigned char ucMarried;

};

这个数据结构定义没有任何问题;相信碰到这种情况,大部分人随手也就这样做了;但实际上如果仔细考虑,完全可以使用享元:理论上同一届的应届生年龄相差不大(3岁差不多了吧),入学时间和毕业时间应该都相同,性别,婚否每个2,那一共有多少种情况呢?32再乘2 = 12

所以我们实际上可以这样考虑下面的设计

struct template {

    unsigned int uiYearEnterCollege;

    unsigned int uiYearGraduate;

    unsigned char ucMonthEnterCollege;

    unsigned char ucMonthGradute;

    unsigned char ucAge;

    unsigned char ucGender;

    unsigned char ucMarried;   

    char cTemplateId;

};

 

struct student {

    unsigned int uiIndex;

    unsigned short usCollegeIndex;

    char cTemplateId;

};

从这里看到的数据,大约会节约12/20 = 60%的空间(当然实际上应该是没有的,因为学生还有很多其它的信息);但这个数据也足够振奋人心的了

但也由此可见,享元并不那么直观,我们需要细心观察和总结;

遗留了一些问题:

1 usCollegeIndex可以抽取到享元中吗?

2 什么时候需要考虑享元?

3 什么样的信息适合抽取出来作为享元?

 

小结

享元是一种设计模式:并不针对面对对象,在c语言,数据库等等领域都有重要的价值;

享元更是一种思路,可共享的才是最好的 这无疑是面对对象的根本要义;在所有的业务领域也不失为一个努力的方向

同时享元还揭示了一个真理:不完美就是一种完美,它用一个不完美的手法达到了完美的效果(感觉有点像易经中阴中有阳,阳中有阴,呵呵);如果你仔细观察,生活中这种例子数不胜数。

享元如此精彩,但又如此朦胧;这不得不要求我们睁大双眼,每日三省代码:这里可以享元吗?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值