1. 作用
享元模式,顾名思义带有共享的意思,的确它就是用于共享对象的.
意图:运用共享技术有效地支持大量细粒度的对象。系统反复使用较少数量的对象,他们差别较小,从而的=达到反复利用的效果。
2. UML类图
参与者:
- Flyweight(抽象享元类):通常是一个抽象类,在抽象享元类中声明了具体享元类公共的方法,这些方法可以向外界提供享元对象的内部数据(内部状态),同时也可以通过这些方法来设置外部数据(外部状态)。
- ConcreteFlyweight(具体享元类):实现了抽象享元类,其实例称为享元对象;在具体享元类中为内部状态提供了存储空间。通常可以结合单例模式来设计具体享元类,为每一个具体享元类提供唯一的享元对象。
- UnsharedConcreteFlyweight(非共享具体享元类):并不是所有抽象享元类的子类都需要被共享,不能被共享的子类可设计为非共享具体享元类,当需要一个非共享具体享元类的对象时可以直接通过实例化创建。
- FlyweightFactory(享元工厂类):用于创建并管理享元对象,它针对抽象享元类编程,将各种类型的具体享元对象存储在一个享元池中,享元池一般设计为一个存储“键值对”的集合(也可以是其他类型的集合),可以结合工厂模式进行设计;当用户请求一个具体享元对象时,享元工厂提供一个存储在享元池中已创建的实例或者创建一个新的实例(如果不存在的话),返回新创建的实例并将其存储在享元池中
3. 实现
- 举例:在做通讯的时候经常要向下位机发送一些命令,一般有状态命令或者控制命令,而不可能每次发命令都重新创建一个命令对象,这种情况就可以使用享元模式了。
- 代码:
#include <iostream>
#include <string>
#include <map>
using namespace std;
class Cmd
{
public:
virtual void setData(string data)
{
m_Data = data;
}
virtual void sendCmd() = 0;
protected:
string m_Data;
};
class StateCmd :public Cmd
{
public:
virtual void sendCmd()
{
cout << "发送状态命令,内容是:" << m_Data << endl;
}
};
class CtrCmd :public Cmd
{
public:
virtual void sendCmd()
{
cout << "发送控制命令,内容是:" << m_Data << endl;
}
};
enum CmdType
{
ENUM_StateCmd,
ENUM_CtrCmd
};
class CmdFactory
{
public:
Cmd * CreateCmd(CmdType cmd)
{
Cmd *p = NULL;
if (m_Cmds.find(cmd) != m_Cmds.end()) {
p = m_Cmds[cmd];
}
else
{
if (cmd == ENUM_StateCmd)
{
p = new StateCmd;
}
else if (cmd == ENUM_CtrCmd)
{
p = new CtrCmd;
}
m_Cmds.insert(std::make_pair(cmd, p));
}
return p;
}
private:
map<CmdType, Cmd*> m_Cmds;
};
int main()
{
CmdFactory *myCmdFactory = new CmdFactory;
Cmd *curCmd;
for (int i = 0; i < 10; ++i)
{
if (i & 0x01)
{
curCmd = myCmdFactory->CreateCmd(ENUM_StateCmd);
}
else
{
curCmd = myCmdFactory->CreateCmd(ENUM_CtrCmd);
}
curCmd->setData(::to_string(i));
curCmd->sendCmd();
}
return 0;
}
结果:
发送控制命令,内容是:0
发送状态命令,内容是:1
发送控制命令,内容是:2
发送状态命令,内容是:3
发送控制命令,内容是:4
发送状态命令,内容是:5
发送控制命令,内容是:6
发送状态命令,内容是:7
发送控制命令,内容是:8
发送状态命令,内容是:9
请按任意键继续. . .
4. 优缺点
-优点:
• 可以极大减少内存中对象的数量,使得相同或相似对象在内存中只保存一份,避免频繁创建销毁兑现,从而可以节约系统资源,提高系统性能。
• 享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享。
缺点:
• 享元模式使得系统变得复杂,需要分离出内部状态和外部状态,这使得程序的逻辑复杂化。
• 为了使对象可以共享,享元模式需要将享元对象的部分状态外部化,而读取外部状态将使得运行时间变长
5. 适用场景
一个系统有大量相同或者相似的对象,造成内存的大量耗费。
对象的大部分状态都可以外部化,可以将这些外部状态传入对象中。
6. 总结
享元模式用于共享对象,但要求上一个客户使用完对象之后才可从对象池中取出对象来共享。