结构型模式7-享元模式
享元模式Flyweight
意图
运用共享技术有效地支持大量细粒度的对象。
问题思考
Word文档。最灵活的方式是对每个字符用一个对象来表示。但由于一篇文档少则几十个字,多则上万,上百万个字符。这种做法会造成非常严重的性能问题。 同时也可以参考网站,每个用户都存在数据库里。需要的时候从数据库里取出来,再渲染html页面呈现给用户。
适用性
- 一个应用程序使用了大量的对象
- 完全由于使用大量的对象,造成很大的存储开销
- 对象的大多数状态都变为外部状态
- 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象
类图
flyweight注意事项
- 删除外部状态。 享元模式的可用在很大程度上取决于是否容易识别外部状态并将它从共享对象中删除。如果不同种类的外部状态和共享前对象的数目相同的话,删除外部状态不会降低存储消耗。理想的状况是,外部状态可以由一个单独的对象结构计算得到,且该结构的存储要求非常小。
- 管理共享对象。 因为对象是共享的,用户不能直接实例化对象,只能通过FlyweightFactory来进行查找。共享还以为着引用计数和垃圾回收。否则会造成内存泄露。
实现
class Flyweight {
public:
explicit Flyweight(const std::string &key) { mKey = key; }
virtual void Operation() = 0;
virtual std::string Key() { return mKey; }
private:
std::string mKey;
};
class ConcreteFlyweight : public Flyweight {
public:
ConcreteFlyweight(const std::string &key) : Flyweight(key) {}
void Operation() override {
// do some stuff
}
};
class UnsharedFlyweight : public Flyweight {
public:
explicit UnsharedFlyweight(const std::string &key) : Flyweight(key) {}
void Operation() override {
// do some stuff
}
};
class FlyweightFactory {
public:
Flyweight *GetFlyweight(const std::string &key) {
Flyweight *fly = nullptr;
auto it = mPool.find(key);
if (it != mPool.end()) {
fly = it->second;
} else {
fly = new ConcreteFlyweight(key);
mPool.emplace(key, fly);
}
return fly;
}
private:
std::map<std::string, Flyweight*> mPool;
};
注意:这里需要客户来决定哪些flyweight是可共享的(可以放在pool中),哪些是不可共享的。请参考《设计模式》中享元模式一节的例子,非常精妙。
网友评论