简介
享元模式(Flyweight Pattern)是一种结构型设计模式,旨在通过共享对象,有效地支持大量细粒度的对象,从而减少内存和性能消耗。它通过将对象分为可共享的内部状态和不可共享的外部状态,从而实现对象共享。
描述
享元模式通过共享对象来减少对象创建和消耗的开销,尤其适用于有大量相似对象的场景。在享元模式中,每个对象被视为两个部分:内部状态和外部状态。内部状态是可以共享的,而外部状态则根据具体的场景而变化。
原理
享元模式的关键是共享对象。当客户端需要创建一个对象时,首先检查对象池中是否已经存在相同的对象,如果存在则返回该对象,如果不存在则创建一个新对象并将其添加到对象池中。通过共享对象,可以减少内存消耗和对象创建的开销。
类图
示例
假设要创建一个游戏中的棋局对象,棋局中有很多棋子,每个棋子有自己的位置和颜色。
为了节省内存和创建开销,可以使用享元模式来共享相同颜色的棋子对象。
在下面的示例中,定义了一个棋子接口 ChessPiece 和一个具体的实现类 ChessPieceImpl,用于表示棋子的内部状态。此外还定义了一个棋子工厂类 ChessPieceFactory,用于创建和管理棋子对象。
#include <>
#include <vector>
#include <unordered_map>
// 棋子接口
class ChessPiece {
public:
virtual void draw(int x, int y) = 0;
};
// 具体的棋子实现类
class ChessPiece : public ChessPiece {
private:
std::string color;
public:
ChessPieceImpl(std::string color) : color(color) {}
void draw(int x, int y) {
std::cout << "Draw a " << color << " chess piece at (" << x << ", " << y << ")" << std::endl;
}
};
// 棋子工厂类
class ChessPieceFactory {
private:
map<std::string, ChessPieceImpl*> chessPieces;
public:
ChessPiece* getChessPiece(std::string color) {
if (chessPieces.find(color) == chessPieces.end()) {
chessPieces[color] = new ChessPieceImpl(color);
}
return chessPieces[color];
}
};
int main() {
ChessPieceFactory factory;
// 绘制黑色棋子
ChessPiece* blackPiece1 = factory.getChessPiece("black");
blackPiece1->draw(0, 0);
// 绘制黑色棋子
ChessPiece* blackPiece2 = factory.getChessPiece("black");
blackPiece2->draw(0, 1);
// 绘制白色棋子
ChessPiece* whitePiece = factory.getChessPiece("white");
whitePiece->draw(1, 1);
// 释放资源
delete blackPiece1;
delete blackPiece2;
delete whitePiece;
return 0;
}
输出结果
Draw a black chess piece at (0, 0)
Draw a black chess piece at (0, 1)
Draw a white chess piece at (1, 1)
解释
在上述示例中,使用了享元模式来共享相同颜色的棋子对象。
首先,创建了一个棋子工厂对象 ChessPieceFactory,用于创建和管理棋子对象。
当客户端需要创建棋子时,首先检查工厂中是否已经存在相颜色的棋子对象,如果存在则返回该对象,不存在则创建一个新的棋子对象并将其到工厂中。
在输出结果中,可以看到,虽然创建了两个黑色的棋子对象,但实际上它们是同一个对象,因为它们共享了相同的内部状态(颜色)。而白色的棋子对象则是一个新创建的对象。
结论
享元模式可以有效地减少内存和对象创建的开销,特别适用于有大量相似对象的场景。通过将对象分为可共享的内部状态和不可共享的外部状态,可以实现对象的共享,提高系统性能。
应用场景
享元模式适用于以下情况:
- 系统中存在大量相似的对象,造成了内存和性能上的浪费。
- 对象的大部分状态可以转化为外部状态。
- 应用不依赖对象标识。