Flyweight(享元)模式 总结


前言

        本周五参加了Flyweitht(享元)模式研讨会,本文的目的是对这个模式的总结和分享,希望对需要学习这个设计模式的同学有所帮助。本文一共分为两个部分,第一个部分是享元模式的基础知识总结;第二个部分是享元模式的一个例子分享。

一、享元模式总结

        

1、模式意图

运用共享技术有效地支持大量细粒度的对象。

2、参与者

Flyweight
--描述一个接口,通过这个接口flyweight可以接受并作用于外部状态;
ConcreteFlyweitht
-- 实现flyweitht接口,并为内部状态增加存储空间;
-- Concrete-flyweight对象必须是可共享的,它所存储的状态必须是内部的,它独立于concrete-flyweight对象的场景;
UnsharedConcreteFlyweight
--非共享对象,Flyweight接口使共享成为可能,但不强制共享;
FlyweightFactory
-- 创建并管理flyweight对象; -- 确保合理的共享flyweight。 -- 当用户请求一个flyweight时,FlyweightFactory对象提供一个已创建的实例,如果不存在,则创建一个新实例并返回;
Client
--维持一个对flyweight的引用;计算或存储flyweight的外部状态;

3、结构及效果

结构图:

在这里插入图片描述

效果:
1、使用flyweight模式时,传输、查找、计算外部状态都会产生运行时开销,尤其是当flyweight原先被存储为内部状态时。
2、由于采用共享方式存储对象,节省存储空间,共享的flyweight越多,节约的空间也越多。

二、享元模式应用示例

1、用例背景描述

         享元模式经典的应用场景之一就是文本编辑器的字体。我们在编辑文本的时候,首先需要选用一种字体,然后设置字体字号。对于同一种字体,都会有非常多细分的字体字号。如下图所示:

在这里插入图片描述

         如果每一种具体的字号都使用一个单独的对象存储,那么,我们在编辑长篇文章时(例如我们编辑一本书),我们电脑的内存将会消耗巨大,电脑配置低的电脑甚至会出现卡顿等现象,严重影响工作心情和工作效率。这时候,享元模式模式的优势就体现得淋漓尽致了。使用享元,一种字体只有一个对象,字号作为享元对象的外部状态,当绘制字符时,把字体信息传递给享元对象即可把字符绘制出来,完全避免了同一种字体,不同字号需要使用独立对象存储的缺陷。

2、用例结构图

在这里插入图片描述

font_factory_t:字体工厂,所有的字体由工厂创建; font_t:抽象字体类; song_font_t:具体的共享字体类,表示宋体; black_font_t:具体的共享字体类,表示黑体; client:客户,使用工厂对象创建字体及使用字体

3、类说明

1、font_t:定义抽象绘制接口,接收外部状态并绘图:
class font_t {
public:
    font_t(font_type_t type);
    font_type_t get_type();//获取字体类型
    virtual draw(ctx_t* ctx, uint32_t font_size);//上下文信息及字号

private:
    font_type_t font_type;
};
2、song_font_t:实现宋体类型的字体,实现宋体的绘制:
class song_font_t : public font_t {
public:
    song_font_t(font_type_t type);
    virtual draw(ctx_t* ctx, uint32_t font_size);//上下文信息及字号
};
3、black_font_t:实现黑体类型的字体,实现黑体的绘制。
class black_font_t : public font_t {
public:
    black_font_t(font_type_t type);
    virtual draw(ctx_t* ctx, uint32_t font_size);//上下文信息及字号
};
4、font_factory:字体工厂,负责所有字体的创建。
class font_factory {
public:
    font_t* create_font(font_type_t type);
    static font_factory* get_factory();

private:
    font_factory();
    static font_factory* factory;
    map<font_type_t, font_t*> font_pool;
};

font_factory* font_factory::factory = NULL;
//cpp
font_factory* font_factory::get_factory() {
    if (factory == NULL) {
        factory = new font_factory();
    }
    
    return factory;
}

font_t* font_factory::create_font(font_type_t type) {
    if (type == SONG_FONT) {
        if (font_pool.find(type) == font_pool.end()) {
            font_pool[type] = new song_font_t(type);
        }

        return font_pool[type];
    }
    
    if (type == BLACK_FONT) {
        if (font_pool.find(type) == font_pool.end()) {
            font_pool[type] = new black_font_t(type);
        }

        return font_pool[type];
    }
    
    return NULL;
}
5、client:客户代码。
...//其他代码,如上下文ctx...

font_factory* font_factory = font_factory::get_factory();//单例模式,获取字体工厂对象
font_t* song1 = font_factory->create_font(SONG_FONT);//会创建宋体对象
font_t* song2 = font_factory->create_font(SONG_FONT);//复用已存在宋体对象,不会重新创建
font_t* song3 = font_factory->create_font(SONG_FONT);//复用已存在宋体对象,不会重新创建
font_t* song4 = font_factory->create_font(SONG_FONT);//复用已存在宋体对象,不会重新创建

song1->draw(ctx, 8);//8号宋体
song2->draw(ctx, 20);//20号宋体
song3->draw(ctx, 60);//60号宋体
song4->draw(ctx, 96);//96号宋体

....

font_t* black1= font_factory->create_font(BLACK_FONT);//会创建黑体对象
font_t* black2= font_factory->create_font(BLACK_FONT);//复用已存在黑体对象,不会重新创建
font_t* black3= font_factory->create_font(BLACK_FONT);//复用已存在黑体对象,不会重新创建
font_t* black4 = font_factory->create_font(BLACK_FONT);//复用已存在黑体对象,不会重新创建

black1->draw(ctx, 8);//8号黑体
black2->draw(ctx, 20);//20号黑体
black3->draw(ctx, 60);//60号黑体
black4 ->draw(ctx, 96);//96号黑体

...//其他处理代码


总结

         享元模式的目的是利用共享技术减少空间消耗。它把可变的部分隔离出来,作为外部状态,把不变的部分作为内部状态,这样,不变的部分就可以共享,实现减少空间消耗的目的。
         享元的创建由工厂统一负责,可以简化客户代码,降低客户代码与具体类之间的耦合程度,便于维护。对于享元工厂,一般采用单例模式实现,工厂类只需一个对象即可。在工厂中,需要维护一个享元对象池,每次创建函数调用时,首先查找对象是否已存在,只有对象不存在时才会创建对象。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值