【重读设计模式】享元模式(蝇量模式)

来源:互联网 发布:指向整形数组的指针 编辑:程序博客网 时间:2024/04/30 15:49

享元模式(又叫蝇量模式)是一个较少见的模式,一般的系统中也较少使用。因为这个模式使用场景较为特殊,更为常见的方式是使用单体模式封装的容器数据用来替换。


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

定义解释:在某些特定的系统中,拥有着巨量的对象,如果每个对象都占用相同大小的内存,将会占用巨量的内存。但是对于这部分对象,其实大多数的属性都是相同的,只有极少数的属性不相同。我们将大部分都相同的部分独立出来,称为内蕴状态,将不相同的部分也独立出来,称为外蕴状态。对于内蕴状态我们只在全局生成一个对象(用单体模式构建),外蕴状态通过参数来确定。


使用场景:

1 一个应用程序使用了大量的对象。
2 完全由于使用大量的对象,造成很大的存储开销。
3 对象的大多数状态都可以变为外部状态。
4 如果删除对象以外的状态那么可以用相对较少的共享对象取代很多组对象。
5 应用程序不依赖于对象标识。


例子:

文档中文字的存储是享元模式的经典例子,一般一篇长篇小说有很多文字,多达数万甚至几十万,但是使用到的字可能才几千,绝大多数都是重复的,某些字比如“的”“我”“地”还有标点符号会重复出现很多次,如果按照一般的一个字一个对象的存储方法,那么会有几万甚至几十万个对象,但是字其实只使用了几千,其他的都是重复的,比如“我”这个字,出现了500次,这500次除了出现的位置不一样,其他不管是编码,还是格式,还是字体,颜色等等都是一样的,如果存储500份几乎一样的数据,那是很浪费内存的。按照享元模式的设计策略,我们本来需要创建几十万个对象,而现在使用享元模式只需要创建几千个对象,再加上字的外部状态(位置和编码),将会大大降低使用的内存。


设计: 

假设字是一个抽象类,具有内部属性,格式(style)颜色(color)字体(fond)大小(size)。我们将会改变的position位置信息作为外部属性。我们为每个字创建一个类(字符集),使用全局唯一的简单工厂和单体模式完成创建。文档存储通过一个vector来记录每个位置出现的字的编码和位置(位置就是下表),我们通过该vector就能完全存储下文档中所有的文字信息。


类图:



实现:

//============================================================================
// Name        : flyweight.cpp
// Author      : tester
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================


#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;


class CWord
{
public:
virtual ~CWord(){};
virtual int show() = 0;


protected:
int m_size;
int m_fond;
int m_style;
int m_color;
};


class CWordA : public CWord
{
public:
CWordA()
{
m_size = 1;
m_fond = 2;
m_style = 3;
m_color = 4;
}
int show()
{
printf("WordA,%d,%d,%d,%d\n",m_size,m_fond,m_style,m_color);
return 0;
}
};


class CWordB : public CWord
{
public:
CWordB()
{
m_size = 2;
m_fond = 3;
m_style = 4;
m_color = 5;
}
int show()
{
printf("WordB,%d,%d,%d,%d\n",m_size,m_fond,m_style,m_color);
return 0;
}
};


class CWordC : public CWord
{
public:
CWordC()
{
m_size = 4;
m_fond = 5;
m_style = 6;
m_color = 7;
}
int show()
{
printf("WordC,%d,%d,%d,%d\n",m_size,m_fond,m_style,m_color);
return 0;
}
};


class CWordFactor
{
public:
CWordFactor()
{
m_wordA = NULL;
m_wordB = NULL;
m_wordC = NULL;
}
CWord* word_factor(const string& name)
{
CWord* word = NULL;
if(name == "A")
{
if(NULL == m_wordA)
{
word = new CWordA;
}
else
{
word = m_wordA;
}
}


if(name == "B")
{
if(NULL == m_wordB)
{
word = new CWordB;
}
else
{
word = m_wordB;
}
}


if(name == "C")
{
if(NULL == m_wordC)
{
word = new CWordC;
}
else
{
word = m_wordC;
}
}


return word;
}
private:
CWord* m_wordA;
CWord* m_wordB;
CWord* m_wordC;
};


class CWordDoc
{
public:
int add_word(CWord* word)
{
m_words.push_back(word);
return 0;
}


void display()
{
for(unsigned idx=0; idx<m_words.size(); ++idx)
{
m_words[idx]->show();
}
}


private:
vector<CWord*> m_words;
};


int main() {
cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!


CWordDoc worddoc;


CWordFactor wordfactor;
CWord* word = wordfactor.word_factor("A");
worddoc.add_word(word);


word = wordfactor.word_factor("B");
worddoc.add_word(word);


word = wordfactor.word_factor("C");
worddoc.add_word(word);


word = wordfactor.word_factor("B");
worddoc.add_word(word);


word = wordfactor.word_factor("A");
worddoc.add_word(word);


word = wordfactor.word_factor("C");
worddoc.add_word(word);


worddoc.display();


return 0;
}


运行结果:

!!!Hello World!!!
WordA,1,2,3,4
WordB,2,3,4,5
WordC,4,5,6,7
WordB,2,3,4,5
WordA,1,2,3,4
WordC,4,5,6,7


总结:

当一个系统中需要存在大量的对象,而且每个对象之间有很多的相同之处,我们通过将对象的属性拆分为变化的和不变化的,变化的称之为外部状态,不变的成为内部状态,将不变的部分定义成独立的对象,并在系统内部共享。这样可以大大降低系统内部的对象量,从而减少内存的占用量。

0 0