简介
享元模式(Flyweight Pattern)是一种结构型设计模式,通过共享技术来高效支持大量细粒度的对象。该模式的核心理念在于共享尽可能多的数据,以减少内存使用。它特别适用于那些数量庞大且状态变化少的对象。
生活中的实例:图形处理中的字体显示
假设你正在开发一个文字处理应用程序,该应用会在屏幕上显示大量的字符。每个字符都有自己的字体、大小、颜色等属性。这些字符的数量可能非常庞大,如果每个字符都独立存储全部的属性,将会占用大量内存。
享元模式可以通过共享字体属性来大幅度减少内存使用量。例如,相同字体、大小和颜色的字符可以共享一份属性数据。
享元模式的实现
享元类
首先,我们定义一个享元类,用于共享字体属性。
#include <iostream>
#include <string>
#include <unordered_map>
// 字体享元类
class Font {
public:
Font(const std::string &fontName, int fontSize, const std::string &fontColor)
: fontName(fontName), fontSize(fontSize), fontColor(fontColor) {}
void display(const std::string &text) {
std::cout << "Displaying text: '" << text << "' with font [Name: " << fontName
<< ", Size: " << fontSize << ", Color: " << fontColor << "]" << std::endl;
}
private:
std::string fontName;
int fontSize;
std::string fontColor;
};
享元工厂类
享元工厂类负责管理和创建享元对象,并确保相同的属性只创建一次
class FontFactory {
public:
Font *getFont(const std::string &fontName, int fontSize, const std::string &fontColor) {
std::string key = fontName + "-" + std::to_string(fontSize) + "-" + fontColor;
if (fonts.find(key) == fonts.end()) {
fonts[key] = new Font(fontName, fontSize, fontColor);
}
return fonts[key];
}
~FontFactory() {
for (auto &pair : fonts) {
delete pair.second;
}
}
private:
std::unordered_map<std::string, Font *> fonts;
};
客户端类
客户端类使用享元模式来显示文本。
class Text {
public:
Text(const std::string &content, Font *font) : content(content), font(font) {}
void display() {
font->display(content);
}
private:
std::string content;
Font *font;
};
使用示例
在主函数中展示如何使用享元模式来有效地管理和显示大量的文本。
int main() {
FontFactory fontFactory;
// 创建一些文本,每段文本使用共享的字体对象
Font *font1 = fontFactory.getFont("Arial", 12, "Black");
Text text1("Hello, World!", font1);
text1.display();
Font *font2 = fontFactory.getFont("Arial", 12, "Black");
Text text2("Flyweight Pattern", font2);
text2.display();
Font *font3 = fontFactory.getFont("Times New Roman", 14, "Red");
Text text3("Design Patterns", font3);
text3.display();
Font *font4 = fontFactory.getFont("Times New Roman", 14, "Red");
Text text4("C++ Programming", font4);
text4.display();
// 使用享元模式,相同属性的字体对象只创建一次
std::cout << "Arial-12-Black font object count: " << (font1 == font2) << std::endl;
std::cout << "Times-14-Red font object count: " << (font3 == font4) << std::endl;
return 0;
}
完整代码
#include <iostream>
#include <string>
#include <unordered_map>
// 字体享元类
class Font {
public:
Font(const std::string &name, int size, const std::string &color)
: name(name), size(size), color(color) {}
void display(const std::string &text) {
std::cout << "Displaying text: '" << text << "' with font [Name: " << name
<< ", Size: " << size << ", Color: " << color << "]" << std::endl;
}
private:
std::string name;
int size;
std::string color;
};
// 享元工厂类
class FontFactory {
public:
Font* getFont(const std::string &name, int size, const std::string &color) {
std::string key = name + std::to_string(size) + color;
if (fonts.find(key) == fonts.end()) {
fonts[key] = new Font(name, size, color);
}
return fonts[key];
}
~FontFactory() {
for (auto &pair : fonts) {
delete pair.second;
}
}
private:
std::unordered_map<std::string, Font*> fonts;
};
// 客户端类
class Text {
public:
Text(const std::string &content, Font *font) : content(content), font(font) {}
void display() {
font->display(content);
}
private:
std::string content;
Font *font;
};
// 主函数
int main() {
FontFactory fontFactory;
// 创建一些文本,每段文本使用共享的字体对象
Font *font1 = fontFactory.getFont("Arial", 12, "Black");
Text text1("Hello, World!", font1);
text1.display();
Font *font2 = fontFactory.getFont("Arial", 12, "Black");
Text text2("Flyweight Pattern", font2);
text2.display();
Font *font3 = fontFactory.getFont("Times New Roman", 14, "Red");
Text text3("Design Patterns", font3);
text3.display();
Font *font4 = fontFactory.getFont("Times New Roman", 14, "Red");
Text text4("C++ Programming", font4);
text4.display();
// 使用享元模式,相同属性的字体对象只创建一次
std::cout << "font1 == font2: " << (font1 == font2) << std::endl;
std::cout << "font3 == font4: " << (font3 == font4) << std::endl;
return 0;
}
解释
- 享元类:
Font
类包含字体的相关属性,并提供一个display
方法来显示文本。 - 享元工厂类:
FontFactory
用于管理和创建具有相同属性的共享字体对象。通过一个键(由字体名称、大小和颜色组成的字符串)来查找和存储享元对象。 - 客户端类:
Text
类封装了文本及其对应的Font
对象,并提供一个display
方法来显示文本。 - 主函数:演示了如何使用享元模式来减少内存使用,确保相同属性的
Font
对象只创建一次。
通过这一示例,你可以看到享元模式如何通过共享技术有效地支持大量细粒度的对象,从而减少内存消耗并提高系统性能。