运用共享技术有效地支持大量细粒度的对象。
享元对象能做到共享的关键是区分内蕴状态(Internal State)和外蕴状态(External State)。
内蕴状态是存储在享元对象内部并且不会随环境改变而改变。因此内蕴状态并可以共享。
外蕴状态是随环境改变而改变的、不可以共享的状态。享元对象的外蕴状态必须由客户端保存,并在享元对象被创建之后,在需要使用的时候再传入到享元对象内部。外蕴状态与内蕴状态是相互独立的。
适用性:
1.当系统中有大量的细粒度对象实例,而且这些对象实例中有一些属性是重复的情况下,考虑使用。
2.文本编辑器,输入法之类的常用应用。
优点:
1.提高了系统的效率,减小了内存的消耗。
2.减少了重复代码。
3.减少了系统的复杂度。
缺点:
1.维护共享对象和查找所需的共享对象需要花费很多时间。
举例
举个围棋的例子,围棋的棋盘共有361格,即可放361个棋子。现在要实现一个围棋程序,该怎么办呢?首先要考虑的是棋子棋盘的实现,可以定义一个棋子的类,成员变量包括棋子的颜色、形状、位置等信息,另外再定义一个棋盘的类,成员变量中有个容器,用于存放棋子的对象。
在围棋中,棋子就是大量细粒度的对象。其属性有内在的,比如颜色、形状等,也有外在的,比如 在棋盘上的位置。内在的属性是可以共享的,区分在于外在属性。因此,可以这样设计,只需定义两个棋子的对象,一颗黑棋和一颗白棋,这两个对象含棋子的内在 属性;棋子的外在属性,即在棋盘上的位置可以提取出来,存放在单独的容器中。相比之前的方案,现在容器中仅仅存放了位置属性,而原来则是棋子对象。显然, 现在的方案大大减少了对于空间的需求。
#include <iostream>
#include <vector>
using namespace std;
//棋子颜色
enum PieceColor {BLACK, WHITE};
//棋子位置
struct PiecePos
{
int x;
int y;
PiecePos(int a, int b): x(a), y(b) {}
};
//棋子定义
class Piece
{
protected:
PieceColor m_color; //颜色
public:
Piece(PieceColor color): m_color(color) {}
~Piece() {}
virtual void Draw() {}
};
//黑棋
class BlackPiece: public Piece
{
public:
BlackPiece(PieceColor color): Piece(color) {}
~BlackPiece() {}
void Draw() { cout<<"绘制一颗黑棋\n"; }
};
//白棋
class WhitePiece: public Piece
{
public:
WhitePiece(PieceColor color): Piece(color) {}
~WhitePiece() {}
void Draw() { cout<<"绘制一颗白棋\n";}
};
//棋盘
class PieceBoard
{
private:
vector<PiecePos> m_vecPos; //存放棋子的位置
Piece *m_blackPiece; //黑棋棋子
Piece *m_whitePiece; //白棋棋子
string m_blackName;
string m_whiteName;
public:
PieceBoard(string black, string white): m_blackName(black), m_whiteName(white)
{
m_blackPiece = NULL;
m_whitePiece = NULL;
}
~PieceBoard() { delete m_blackPiece; delete m_whitePiece;}
void SetPiece(PieceColor color, PiecePos pos)
{
if(color == BLACK)
{
if(m_blackPiece == NULL) //只有一颗黑棋
m_blackPiece = new BlackPiece(color);
cout<<m_blackName<<"在位置("<<pos.x<<','<<pos.y<<")";
m_blackPiece->Draw();
}
else
{
if(m_whitePiece == NULL)
m_whitePiece = new WhitePiece(color);
cout<<m_whiteName<<"在位置("<<pos.x<<','<<pos.y<<")";
m_whitePiece->Draw();
}
m_vecPos.push_back(pos);
}
};
int main()
{
PieceBoard pieceBoard("A","B");
pieceBoard.SetPiece(BLACK, PiecePos(4, 4));
pieceBoard.SetPiece(WHITE, PiecePos(4, 16));
pieceBoard.SetPiece(BLACK, PiecePos(16, 4));
pieceBoard.SetPiece(WHITE, PiecePos(16, 16));
}