享元模式应用环境:存在大量对象存储,而且这些对象之间存在较大的相似性,可以应用享元模式,将其相似特征抽象为共享对象,通过这些共享对象来替换以前的大量的相似对象。
比较经典的例子:围棋中的棋子。对于棋盘中的棋子来说,它有位置,颜色等重要特性,如果将这些特性都封装在棋子对象中,那下一盘棋,因为每一个位置的棋子都是一个新的对象,那可能就需要数百个对象。这大大的耗费了内存。
但如果将棋子的不同特征拿出来单独存储,并将相似特征提取出来做为共享对象,那就能大大缩减对象的存储量。比如,将棋子中特征各异的位置信息提取出来单独存储,将颜色特征提取出来抽象共享对象,那我们只需要2个对象就可以——一个黑棋和一个白棋。将数百个棋子对象通过这种方式抽象为2个对象的方式,就称为享元模式。
为了加深对比,下面分别附上正常状态的棋子棋盘类和应用享元模式后的棋子棋盘类。
正常状态:
#include
#include
#include
using namespace std;
//棋子在棋盘的位置信息
class ChessmanPos
{
public:
ChessmanPos(int x, int y) :m_x(x), m_y(y) {}
public:
int m_x;
int m_y;
};
//棋子的颜色信息
enum ChessmanColor
{
white=0,
black
};
//棋子父类
class Chessman
{
public:
Chessman(ChessmanColor color, ChessmanPos pos) :m_color(color), m_pos(pos) {}
~Chessman() {};
protected:
ChessmanColor m_color;
ChessmanPos m_pos;
};
//白棋类
class WhiteChessman :public Chessman
{
public:
WhiteChessman(ChessmanColor color, ChessmanPos pos) :Chessman(color, pos) {}
~WhiteChessman() {};
};
//黑棋类
class BlackChessman :public Chessman
{
public:
BlackChessman(ChessmanColor color, ChessmanPos pos) :Chessman(color, pos) {}
~BlackChessman() {};
};
//棋盘类
class ChessmanBoard
{
public:
ChessmanBoard(){}
void putChessman(ChessmanColor color, ChessmanPos pos)
{
Chessman *chessman = NULL;
if (color == white)
{
chessman = new WhiteChessman(color, pos);
}
else
{
chessman = new BlackChessman(color, pos);
}
m_chessmanVector.push_back(chessman);
}
~ChessmanBoard()
{
//别忘了析构
}
private:
vector<Chessman*> m_chessmanVector;
};
void main()
{
ChessmanBoard my_board;
my_board.putChessman(white, ChessmanPos(1, 1));
my_board.putChessman(white, ChessmanPos(1, 2));
my_board.putChessman(black, ChessmanPos(1, 5));
my_board.putChessman(black, ChessmanPos(2, 1));
my_board.putChessman(black, ChessmanPos(2, 2));
return;
}
如上所示,如果是按照一个棋子一个对象来写的话,你棋盘上放置多少个棋子,你就需要new多少个对象,这是在是太复杂了。
下面是享元模式下的代码:
#include
#include
#include
using namespace std;
//棋子在棋盘的位置信息
class ChessmanPos
{
public:
ChessmanPos(int x, int y) :m_x(x), m_y(y) {}
public:
int m_x;
int m_y;
};
//棋子的颜色信息
enum ChessmanColor
{
white = 0,
black
};
//棋子父类
class Chessman
{
public:
Chessman(ChessmanColor color) :m_color(color) {}
~Chessman() {};
protected:
ChessmanColor m_color;
};
//白棋类
class WhiteChessman :public Chessman
{
public:
WhiteChessman(ChessmanColor color) :Chessman(color) {}
~WhiteChessman() {};
};
//黑棋类
class BlackChessman :public Chessman
{
public:
BlackChessman(ChessmanColor color) :Chessman(color) {}
~BlackChessman() {};
};
//棋盘类
class ChessmanBoard
{
public:
ChessmanBoard()
{
whiteChessman = NULL;
blackChessman = NULL;
}
void putChessman(ChessmanColor color, ChessmanPos pos)
{
if (color == white)
{
if (whiteChessman == NULL)
{
whiteChessman = new WhiteChessman(white);
}
}
else
{
if (blackChessman == NULL)
{
blackChessman = new BlackChessman(black);
}
}
m_chessPosVector.push_back(pos);
}
~ChessmanBoard()
{
//别忘了析构
}
private:
vector<ChessmanPos> m_chessPosVector;
WhiteChessman *whiteChessman;
BlackChessman *blackChessman;
};
void main()
{
ChessmanBoard my_board;
my_board.putChessman(white, ChessmanPos(1, 1));
my_board.putChessman(white, ChessmanPos(1, 2));
my_board.putChessman(black, ChessmanPos(1, 5));
my_board.putChessman(black, ChessmanPos(2, 1));
my_board.putChessman(black, ChessmanPos(2, 2));
return;
}
如上所示,整个棋盘,数百颗棋子,只需要2个对象就可以了。
注:上述代码实例是我看了
https://blog.csdn.net/wuzhekai1985/article/details/6670298
这个博主的博客中所举的例子后,自己凭记忆复写出来的,发现这里面存在一个很大的问题:就是我们只知道在哪些位置上有棋子,而不知道保存在该位置的棋子是黑子还是白子?所以,这里我们提取出的差异特征不仅仅是位置,还应该有颜色。当然,设计模式重在思想,感觉这个例子是我看过的享元模式实例中比较经典的,通俗易懂,思想鲜明。