享元模式(Flyweight Pattern)是一种结构型设计模式,用于通过共享相似对象来减少内存使用和提高性能。该模式特别适用于需要大量相似对象的场景,通过将对象的状态分为内部状态和外部状态,来实现高效的对象共享。
享元模式也称为蝇量模式,旨在解决面向对象程序设计中的性能问题。享元的英文名“Flyweight”意为“轻量级”,源于拳击比赛中较轻的选手。该模式的核心目标是让对象变得“轻”,即减少内存占用。在需要某个对象时,尽量共享已经创建的同类对象,以避免频繁使用 new
创建同类或相似的对象。在对象数量非常庞大的情况下,这种共享可以显著节省内存占用并提升程序运行效率。
以下是一个简单的享元模式示例,模拟一个棋盘游戏中的棋子绘制系统,其中可能会有大量相似的棋子对象。
定义棋子的基本结构。EnumColor
枚举表示棋子的颜色,Position
结构体表示棋子的位置。Piece
是一个抽象类,定义了绘制棋子的接口。
enum EnumColor //棋子颜色
{
Black, //黑
White //白
};
struct Position //棋子位置
{
int m_x;
int m_y;
Position(int tmpx, int tmpy) :m_x(tmpx), m_y(tmpy) {} //构造函数
};
class Piece //棋子抽象类
{
public:
virtual ~Piece() {} //做父类时析构函数应该为虚函数
public:
virtual void draw(Position tmppos) = 0;
};
实现具体的棋子类,分别为黑色和白色棋子。每个类实现了 draw
方法,负责在指定位置绘制棋子。通过共享这些具体棋子类,减少内存使用。
class BlackPiece : public Piece //黑色棋子
{
public:
virtual void draw(Position tmppos)
{
cout << "在位置:(" << tmppos.m_x << "," << tmppos.m_y << ")处绘制了一个黑色棋子!" << endl;
}
};
class WhitePiece : public Piece //白色棋子
{
public:
virtual void draw(Position tmppos)
{
cout << "在位置:(" << tmppos.m_x << "," << tmppos.m_y << ")处绘制了一个白色棋子!" << endl;
}
};
工厂类负责创建和管理棋子对象。它使用 std::map
存储已经创建的棋子对象,以便在需要时返回共享的对象。析构函数确保释放内存,防止内存泄漏。
class pieceFactory //创建棋子的工厂
{
public:
~pieceFactory() //析构函数
{
//释放内存
for (auto iter = m_FlyWeihgtMap.begin(); iter != m_FlyWeihgtMap.end(); ++iter)
{
Piece* tmpfw = iter->second;
delete tmpfw;
}
m_FlyWeihgtMap.clear();//这句其实可有可无
}
public:
Piece* getFlyWeight(EnumColor tmpcolor) //获取享元对象,也就是获取被共享的棋子对象
{
auto iter = m_FlyWeihgtMap.find(tmpcolor);
if (iter == m_FlyWeihgtMap.end())
{
//没有该享元对象,那么就创建出来
Piece* tmpfw = nullptr;
if (tmpcolor == Black) //黑子
{
tmpfw = new BlackPiece();
}
else //白子
{
tmpfw = new WhitePiece();
}
m_FlyWeihgtMap.insert(make_pair(tmpcolor, tmpfw));//以棋子颜色枚举值为key,增加条目到map中
return tmpfw;
}
else
{
return iter->second;
}
}
private:
//在文件头增加#include <map>
std::map<EnumColor, Piece*> m_FlyWeihgtMap; //用map容器来保存所有的享元对象,一共就两个享元对象(黑色棋子一个,白色棋子一个)
};
int main()
{
pieceFactory* pfactory = new pieceFactory();
Piece* p_piece1 = pfactory->getFlyWeight(Black);
p_piece1->draw(Position(3, 3));//黑子落子到3,3位置
Piece* p_piece2 = pfactory->getFlyWeight(White);
p_piece2->draw(Position(5, 5));//白子落子到5,5位置
Piece* p_piece3 = pfactory->getFlyWeight(Black);
p_piece3->draw(Position(4, 6));//黑子落子到4,6位置
Piece* p_piece4 = pfactory->getFlyWeight(White);
p_piece4->draw(Position(5, 7));//白子落子到5,7位置
//释放资源
delete pfactory;
return 0;
}
执行结果:
在位置:(3,3)处绘制了一个黑色棋子!
在位置:(5,5)处绘制了一个白色棋子!
在位置:(4,6)处绘制了一个黑色棋子!
在位置:(5,7)处绘制了一个白色棋子!
Piece
,方法是 draw
,外部状态(棋子的位置)通过 draw
方法的参数传递。BlackPiece
和 WhitePiece
类。std::map
存储键值对)。当用户请求一个享元对象时,该工厂返回一个已创建的享元对象,或者如果请求的对象不存在,则新创建一个并放入享元池。#include <iostream>
#include <list>
#include <map>
using namespace std;
enum EnumColor //棋子颜色
{
Black, //黑
White //白
};
struct Position //棋子位置
{
int m_x;
int m_y;
Position(int tmpx, int tmpy) :m_x(tmpx), m_y(tmpy) {} //构造函数
};
class Piece //棋子抽象类
{
public:
virtual ~Piece() {} //做父类时析构函数应该为虚函数
public:
virtual void draw(Position tmppos) = 0;
};
class BlackPiece : public Piece //黑色棋子
{
public:
virtual void draw(Position tmppos)
{
cout << "在位置:(" << tmppos.m_x << "," << tmppos.m_y << ")处绘制了一个黑色棋子!" << endl;
}
};
class WhitePiece : public Piece //白色棋子
{
public:
virtual void draw(Position tmppos)
{
cout << "在位置:(" << tmppos.m_x << "," << tmppos.m_y << ")处绘制了一个白色棋子!" << endl;
}
};
class pieceFactory //创建棋子的工厂
{
public:
~pieceFactory() //析构函数
{
//释放内存
for (auto iter = m_FlyWeihgtMap.begin(); iter != m_FlyWeihgtMap.end(); ++iter)
{
Piece* tmpfw = iter->second;
delete tmpfw;
}
m_FlyWeihgtMap.clear();//这句其实可有可无
}
public:
Piece* getFlyWeight(EnumColor tmpcolor) //获取享元对象,也就是获取被共享的棋子对象
{
auto iter = m_FlyWeihgtMap.find(tmpcolor);
if (iter == m_FlyWeihgtMap.end())
{
//没有该享元对象,那么就创建出来
Piece* tmpfw = nullptr;
if (tmpcolor == Black) //黑子
{
tmpfw = new BlackPiece();
}
else //白子
{
tmpfw = new WhitePiece();
}
m_FlyWeihgtMap.insert(make_pair(tmpcolor, tmpfw));//以棋子颜色枚举值为key,增加条目到map中
return tmpfw;
}
else
{
return iter->second;
}
}
private:
//在文件头增加#include <map>
std::map<EnumColor, Piece*> m_FlyWeihgtMap; //用map容器来保存所有的享元对象,一共就两个享元对象(黑色棋子一个,白色棋子一个)
};
int main()
{
pieceFactory* pfactory = new pieceFactory();
Piece* p_piece1 = pfactory->getFlyWeight(Black);
p_piece1->draw(Position(3, 3));//黑子落子到3,3位置
Piece* p_piece2 = pfactory->getFlyWeight(White);
p_piece2->draw(Position(5, 5));//白子落子到5,5位置
Piece* p_piece3 = pfactory->getFlyWeight(Black);
p_piece3->draw(Position(4, 6));//黑子落子到4,6位置
Piece* p_piece4 = pfactory->getFlyWeight(White);
p_piece4->draw(Position(5, 7));//白子落子到5,7位置
//释放资源
delete pfactory;
return 0;
}