想想我们编辑文档用的office,文档里文字很多都是重复的,我们不可能为每一个出现的汉字都创建独立的空间,这样代价太大,最好的办法就是共享其中相同的部分,使得需要创建的对象降到最小,这个就是享元模式的核心,即运用共享技术有效地支持大量细粒度的对象。
享元对象能做到共享的关键是区分内蕴状态(Internal State)和外蕴状态(External State)。
内蕴状态是存储在享元对象内部并且不会随环境改变而改变。因此内蕴状态并可以共享。
外蕴状态是随环境改变而改变的、不可以共享的状态。
享元对象的外蕴状态必须由客户端保存,并在享元对象被创建之后,在需要使用的时候再传入到享元对象内部。外蕴状态与内蕴状态是相互独立的。
#include <iostream>
#include <map>
using namespace std;
// 抽象享元类(字符)
class Character
{
public:
virtual void set_size(int weight, int height) = 0;
virtual void show() = 0;
protected:
char m_ch; // 内部状态
int m_weight; // 外部状态
int m_height;
};
// 具体享元类(字符A)
class CharacterA : public Character
{
public:
CharacterA()
{
this->m_ch = 'A';
this->m_weight = 100;
this->m_height = 200;
}
void set_size(int weight, int height)
{
this->m_weight = weight;
this->m_weight = height;
}
void show()
{
cout << "CharacterA: " << m_ch << "(" << m_weight << "," << m_height << ")" << endl;
}
};
// 具体享元类(字符B)
class CharacterB : public Character
{
public:
CharacterB()
{
this->m_ch = 'B';
this->m_weight = 200;
this->m_height = 300;
}
void set_size(int weight, int height)
{
this->m_weight = weight;
this->m_weight = height;
}
void show()
{
cout << "CharacterB: " << m_ch << "(" << m_weight << "," << m_height << ")" << endl;
}
};
// 享元工厂类:提供一个用于存储享元对象的享元池,当需要对象时,首先从享元池中获取
class CharacterFactory
{
public:
CharacterFactory()
{
m_char.insert(make_pair<char, Character*>('A', new CharacterA));
m_char.insert(make_pair<char, Character*>('B', new CharacterB));
}
Character* get_char(char ch)
{
map<char, Character*>::iterator it = m_char.find(ch);
if (it != m_char.end())
{
return (Character*)it->second;
}
return NULL;
}
private:
// 存储字符的享元池
map<char, Character*> m_char;
};
void test_01()
{
CharacterFactory* pFactory = new CharacterFactory;
//内部状态(存储在享元对象内部并且不会随环境改变而改变)
Character* ch1 = pFactory->get_char('A');
ch1->show();
//外部状态(客户端保存)
Character* ch2 = pFactory->get_char('B');
ch2->set_size(500, 800);
ch2->show();
}
int main()
{
test_01();
system("pause");
return 0;
}