特征
复用对象(更准确地说是复用对象的部分属性)
目的
减少对象数量,减轻内存压力。减少对象创建,性能也有一定提升。
详情
五指棋游戏,棋盘上有数量大于2的棋子,但种类只有两种,黑子和白子。除了颜色其余参数完全相同(暂时不说坐标)。
既然如此,我们每次落子时是否需要为该棋子单独创建一个对象呢?至少在该模式下不用。
enum COLOR
{
C_BLACK = 0,
C_WHITE = 1,
}
class Chess
{
Chess(COLOR c,int r = 2);
draw();
COLOR color;
int radius;
int pos_x;
int pos_y;
}
上述类中有坐标属性pos_x,pos_y表示在棋盘上的位置,radius表示棋子的半径,color表示棋子颜色,我们这里用它来作为key值区分黑白子。
通常我们需要一个工厂类来作为管理这些对象的工具:
class ChessFactory
{
static Chess getChess(COLOR c);
static std::map<COLOR,Chess> m_chess;
}
std::map<COLOR,Chess> ChessFactory::m_chess = std::map(0)
Chess ChessFactory::getChess(COLOR c)
{
if(m_chess.find(c) == m_chess.end())
{
m_chess[c] = new Chess(c);
}
return m_chess[c];
}
每次落子时我们只需要从该工厂取出棋子便好,如果没有则立即创建,可以想象得到,满棋盘的棋子实际上就只构造了两次。
有个外部环境用于落子:
void play(COLOR c,int pos_x,int pos_y)
{
Chess chess = ChessFactory::getChess(c);
chess.pos_x = pos_x;
chess.pos_y = pos_y;
chess.draw();
}
不用理会语法,语法肯定有问题的,表达意思就行。
可以看到上面的例子我们仅仅创建了两个对象,用颜色区分。同时对象还有pos_x和pos_y两个坐标属性,棋盘上的每颗棋子的坐标都应该不同,因此这里我们将其作为外部数据传入chess对象中。
这其实也是享元模式的一个特性,我们需要区分外部状态和内部状态,内部状态即上述的坐标属性;外部状态其实就是棋子的半径,即棋子能被复用的特征,或者说固有特性,直接点说就是棋子的外观(一个半径固定的圆)。
总结
精髓在于共享,其次需要区分外部和内部状态。
可能我的理解不到位,欢迎大佬批评指正。