享元模式
享元模式(FlyWeight),运用共享技术有效的支持大量细粒度的对象。
分为两个状态:
内蕴状态存储在享元内部,不会随环境的改变而有所不同,是可以共享的。
外蕴状态是不可以共享的,它随环境的改变而改变的,因此外蕴状态是由客户端来保持(因为环境的变化是由客户端引起的)。
--百度百科
就拿常用的五子棋来进行举例,如果按照常规的实现方式,每次拿出一个棋子的时候就去创建一个新的对象,那么当一盘棋下完的时候,会造成内存的极大浪费,因为很多都是相同的数据。
当分析的时候,会发现每个棋子,相同地方在于材质、大小、形状等等,而不同在于颜色和位置。而当进一步区分,将棋子分为白棋子和黑棋子,那么一类棋子不同就只在于位置不同了,这就会导致在用享元模式实现的时候会有两种方法。
- 将棋子分为黑白两种棋子
- 将所有棋子视为一种棋子,其中的颜色只是一个外部通过函数进行设定的参数
我选择的是第一种,因此在设定的时候,黑白棋子为两个类,共同的参数就是棋子的材质等等,而不同的在于位置。
对于状态的区分的话,可以视为:
相同的不会通过函数进行改变的就是内部;而需要通过函数进行外部改变的就是外部。
我用五子棋进行分析享元模式的时候,遇到了一个问题:都是同一个对象,修改后,前面的一个对象哪里去了。
我最后相通的回答是:
- 前面的对象没有被销毁,因为拿五子棋来举例,前一个棋子已经被绘制完了,没有被销毁,因此还是会显示,但是对于是否连线等判断是通过另外一套逻辑进行判断,比如一个矩阵记录所有棋子的位置。而拓展开来就是,享元模式只是提供你所需要的一个对象,去绘制图等等,但是实际涉及到的修改等等是另外一个相附的逻辑。
- 另外一种就是理解为再次享元获取,就是以你修改的属性作为标准,再去对象池进行搜寻例如:
string s1 = "abc";
string s2 = "abc";
cout << (s1 == s2) << endl;
s2 = "abcd";
cout << s1 << endl;
cout << s2 << endl;
结果是1.
abc
abcd
可是当你修改一个的时候,只是修改了一个,因为你修改后,s2再去享元数组搜寻,没找到就重新创建了给对象。
图片来自《大话设计模式》--享元模式 ,如有侵权,请联系作者进行删除,麻烦了。
优点:
- 避免重复创建对象,节省内存空间
- 随区随用,没有就会被创建,用的时候才会创建
// FlyweightModel.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include <iostream>
#include <map>
#include <string>
using namespace std;
enum EChessType
{
white = 0,
black,
};
class CChese
{
//内部状态
//可视为绘制棋子的大小、状态、形状等等
protected:
string m_describe;
protected:
//外部状态
//通过外部接口进行设置
//而在此处将黑白棋子进行了分类,因此在实现的时候就没有提供接口
EChessType m_chessType;
int m_x;
int m_y;
public:
virtual void draw() = 0;
//void setType(EChessType type) {m_chessType = type}
void setPoint(int x, int y) { m_x = x; m_y = y; }
};
//关于黑白棋子的具体实现
//关于设计模式种提到的为i共享对象,我目前开发过程中为涉及到
//所以我没有进行描述或者创建
//如果进行猜想,可能适用于规则中的特定标定,类似于某个公司需要的特殊效果等等
class CWhiteChese :public CChese
{
public:
CWhiteChese(string describe) {
m_describe = describe; m_chessType = white;
cout << "一个白棋子被制造了。" << endl;
}
void draw()
{
cout << "在(" << m_x<<","<<m_y<<")处放白色棋子." << endl;
}
};
class CBlackChese :public CChese
{
public:
CBlackChese(string describe) {
m_describe = describe; m_chessType = black;
cout << "一个黑棋子被制造了。" << endl;
}
void draw()
{
cout << "在(" << m_x << "," << m_y << ")处放黑色棋子." << endl;
}
};
class CCheseFactory
{
private:
map<int, CChese*> m_chese;
public:
CCheseFactory() {}
~CCheseFactory()
{
map<int, CChese*>::iterator iteror = m_chese.begin();
for (iteror ; iteror != m_chese.end() ; ++iteror)
{
delete iteror->second;
}
}
CChese* getChese(int type)
{
map<int, CChese*>::iterator iteror = m_chese.find(type);
if (iteror != m_chese.end())
{
return (CChese*)iteror->second;
}
else
{
CChese* temp = NULL;
if (type == white)
{
temp = new CWhiteChese("一个旗子的所大小,形状等等。");
//temp->setType;
}
else if (type == black)
{
temp = new CBlackChese("一个旗子的所大小,形状等等。");
//temp->setType;
}
if (temp != NULL)
m_chese[type] = temp;
return temp;
}
}
};
int main()
{
//工厂
CCheseFactory fact;
//白棋子
CChese* withe1 = fact.getChese(white);
withe1->setPoint(1, 1);
withe1->draw();
CChese* withe2 = fact.getChese(white);
withe2->setPoint(2, 2);
withe2->draw();
//黑棋子
CChese* black1 = fact.getChese(black);
black1->setPoint(1, 2);
black1->draw();
CChese* black2 = fact.getChese(black);
black2->setPoint(2, 1);
black2->draw();
string s1 = "abc";
string s2 = "abc";
cout << (s1 == s2) << endl;
s2 = "abcd";
cout << s1 << endl;
cout << s2 << endl;
}