FlyWeight模式——设计模式学习笔记
FlyWeight模式
一 意图
运用共享技术有效地支持大量细粒度的对象。
二 动机
有些应用程序得益于在其整个设计过程中采用对象技术,但简单化的实现代价极大。
使用面向对象的抽象化,可能会造成庞大的对象群,造成空间的巨大消耗,而影响性能。
在文档编辑器例子中如果一个字符对应一个对象,那么一篇文档所要容纳的对象将是非常的庞大耗费大量的内存。
而实际组成文档的字符是有限的,是由这些字符不同的组合和排列得到的。
所以需要共享,将基本的字符进行共享,将使得字符对象变得有限。
Flyweight只存储相应的字符代码
这里的关键概念是内部状态和外部状态之间的区别。
内部状态存储于flyweight中,它包含了独立于flyweight场景的信息,这些信息使得flyweight可以被共享。
如字符代码,字符大小……
外部状态取决于flyweight场景,并根据场景而变化,因此不可共享。用户对象负责在必要的时候将外部状态传递给flyweight。
如字符位置,字符颜色……
三 适用性及其结构
当以下情况都成立时使用Flyweight模式:
•一个应用程序使用了大量的对象。
• 完全由于使用大量的对象,造成很大的存储开销。
• 对象的大多数状态都可变为外部状态。
• 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象。
• 应用程序不依赖于对象标识。由于Flyweight对象可以被共享,对于概念上明显有别的对象,标识测试将返回真值。
结构:
description:
•Flyweight
— 描述一个接口,通过这个接口Flyweight可以接受并作用于外部状态。
• ConcreteFlyweight
— 实现Flyweight接口, 并为内部状态( 如果有的话) 增加存储空间。
ConcreteFlyweight对象必须是可共享的。它所存储的状态必须是内部的;即,它必
须独立于Concrete Flyweight对象的场景。
• UnsharedConcreteFlyweight
— 并非所有的Flyweight子类都需要被共享。Flyweight接口使共享成为可能,但它并不强制共享。在Flyweight对象结构的某些层次, UnsharedConcreteFlyweight对象通常
将ConcreteFlyweight对象作为子节点(Row和Conum就是这样)。
• FlyweightFactory
— 创建并管理Flyweight对象。
— 确保合理地共享Flyweight。当用户请求一个Flyweight时,FlyweightFactory对象提供一个已创建的实例或者创建一个(如果不存在的话)。
• Client
— 维持一个对Flyweight的引用。
— 计算或存储一个(多个)Flyweight的外部状态。
Analysis:
Flyweight执行时所需的状态必定是内部的或外部的。内部状态存储于ConcreteFlyweight对象之中;
而外部对象则由C l i e n t对象存储或计算。当用户调用Flyweight对象的操作时,将该状态传递给它。
• 用户不应直接对ConcreteFlyweight类进行实例化,而只能从FlyweightFactory对象得到ConcreteFlyweight对象,
这可以保证对它们适当地进行共享。
存储节约由以下几个因素决定:
• 因为共享,实例总数减少的数目
• 对象内部状态的平均数目
• 外部状态是计算的还是存储的
四 代码实现
Note:
删除外部状态:该模式的可用性在很大程度上取决于是否容易识别外部状态并将它从
共享对象中删除
管理共享对象:引用计数和垃圾回收……
Example :象棋中的棋局中的棋子,任何棋局都是32个 棋子的不同组合。
1 Flyweight
Chess提供了外部状态的设置
/*----------------------------------------------------------------*/
/* class Object */
/*----------------------------------------------------------------*/
class Object
{
};
/*----------------------------------------------------------------*/
/* class Chess */
/*----------------------------------------------------------------*/
class Chess: public Object
{
public:
Chess(){}
void setShape(int shape){}
void setSize(int size){}
void setHeight(int height){}
void setPos(int pos){}
virtual void draw()
{
cout<<"Chess draw"<<endl;
}
private:
int m_shape;
int m_size;
int m_height;
int m_pos;
};
CChess保存内部状态
/*----------------------------------------------------------------*/
/* class CChess */
/*----------------------------------------------------------------*/
class CChess: public Chess
{
public:
CChess(int code)
{
m_code = code;
}
virtual void draw()
{
cout<<"CChess draw"<<endl;
}
private:
int m_code;
};
ChessFactory提供创建享元CChess的接口
/*----------------------------------------------------------------*/
/* class ChessFactory */
/*----------------------------------------------------------------*/
class ChessFactory: public Object
{
#define CHECSS_MAX_NUM (16)
#define CHESS_CODE_OFFSET (0x1000)
class ChessCodeMap
{
public:
int m_code;
CChess* m_chess;
};
public:
ChessFactory()
{
for (int i = 0; i < CHECSS_MAX_NUM; i++)
{
m_chessMap[i].m_chess = NULL;
m_chessMap[i].m_code = i;
}
}
CChess* createChess(int code)
{
for (int i = 0; i < CHECSS_MAX_NUM; i++)
{
if (m_chessMap[i].m_code == code)
{
if (m_chessMap[i].m_chess == NULL)
{
m_chessMap[i].m_chess = new CChess(code);
}
return m_chessMap[i].m_chess;
}
}
return NULL;
}
private:
ChessCodeMap m_chessMap[CHECSS_MAX_NUM];
};
Test
#include "flyweight.h"
int main()
{
ChessFactory* chessFc = new ChessFactory();
CChess* chess = chessFc->createChess(1);
chess->draw();
return 0;
}