享元模式 – 共享对象,节省内存
享元模式(Flyweight Pattern)是一种用于性能优化的模式,其核心是运用共享技术来有效支持大量细粒度的对象。享元模式可以避免大量非常相似类的开销。在程序设计中,有时我们需要生成大量细粒度的类实例来表示数据。如果能发现这些实例除了几个参数外基本上都是相同的,有时候就能够大幅度地减少需要实例化的类的数量。如果能把那些参数移到类实例的外面,在方法调用时传递进来,就可以通过共享大幅度地减少单个实例的数目。
组成
享元工厂(FlyweightFactory):享元工厂是一个用于创建并管理享元对象的工厂类,它主要用来确保合理地共享享元,当用户请求一个享元时,享元工厂提供一个已创建的实例或者创建一个(如果不存在的话)。
抽象享元类(Abstract Flyweight):这是一个接口或抽象类,声明了具体享元类公共的方法,这些方法可以向外界提供享元对象的内部状态,同时也可以通过这些方法来设置外部状态。
具体享元类(Concrete Flyweight):实现抽象享元类,并为内部状态增加存储空间。
非共享具体享元类(Unshared Concrete Flyweight):并非所有的抽象享元类的子类都需要被共享,不能被共享的子类可设计为非共享具体享元类。
客户类(Client):客户类持有一个对抽象享元类的引用,计算或存储一个(或多个)抽象享元类的外部状态。
在享元模式中,内部状态存
好处
- 它可以极大地减少内存中对象的数量,使得相同对象或相似对象在内存中只保存一份。
- 它可以防止大量相似类的开销,这样可以提高系统的性能。
缺点
- 它使得系统更加复杂,需要分离出内部状态和外部状态,而外部状态具有固化特性,一旦修改就可能会导致系统的行为异常。
使用场景
-
系统中存在大量的相似对象:享元模式通过共享技术实现相同或相似对象的重用。
-
这些对象消耗大量的内存:一些系统中,大量使用了对象,造成了大量的内存消耗,可以考虑使用享元模式。
-
对象的状态大部分可以外部化:享元模式把对象的属性划分为内部状态和外部状态,内部状态储存在享元对象内部,而外部状态应当由客户端来考虑。
-
清除对象的外部状态可以削减对象数量:如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象,此时可以考虑使用享元模式。
实现
- 创建一个享元工厂
class FlyweightFactory {
public:
FlyweightFactory() {}
~FlyweightFactory() {}
// 获取享元对象
Flyweight* GetFlyweight(string key) {
if (m_flyweightMap.find(key) == m_flyweightMap.end()) {
m_flyweightMap[key] = new ConcreteFlyweight();
}
return m_flyweightMap[key];
}
private:
map<string, Flyweight*> m_flyweightMap;
};
- 享元基类
class Flyweight {
public:
Flyweight() {}
virtual ~Flyweight() {}
virtual void Operation() = 0;
};
- 具体享元类
class ConcreteFlyweight : public Flyweight {
public:
ConcreteFlyweight() {}
~ConcreteFlyweight() {}
void Operation() {
cout << "ConcreteFlyweight Operation" << endl;
}
};
- 不需要共享的享元类
class UnsharedConcreteFlyweight : public Flyweight {
public:
UnsharedConcreteFlyweight() {}
~UnsharedConcreteFlyweight() {}
void Operation() {
cout << "UnsharedConcreteFlyweight Operation" << endl;
}
};