diff --git a/12_flyweight.cpp b/12_flyweight.cpp new file mode 100644 index 0000000..a96c0e4 --- /dev/null +++ b/12_flyweight.cpp @@ -0,0 +1,52 @@ +#include +#include +#include + + +using namespace std; + +class Model { + string s; +public: + static int cnt; + Model(const string& s) : s(s) { + // Load model from file. + cout << "Loading model: " << s << endl; + cnt += 1; + } +}; + +int Model::cnt = 0; + +class ModelFactory { + map> cache; +public: + shared_ptr get_model(const string& s) { + auto it = cache.find(s); + if (it == cache.end()) { + auto ret = make_shared(s); + cache[s] = ret; + return ret; + } + + return it->second; + } +}; + +struct Monster { +public: + int x; + int y; + shared_ptr t; +}; + + +int main() { + ModelFactory f; + Monster m1{1, 1, f.get_model("pikachu")}; + Monster m2{2, 1, f.get_model("pikachu")}; + Monster m3{1, 2, f.get_model("snorlax")}; + Monster m4{2, 2, f.get_model("pikachu")}; + + cout << "Create " << Model::cnt << " models in memory" << endl; +} diff --git a/notes.md b/notes.md index ba746fa..98c78e7 100644 --- a/notes.md +++ b/notes.md @@ -77,3 +77,9 @@ 在一个复杂系统中,往往由多个子系统协同工作来完成一项功能。例如,一个编译器可能包含词法分析器、语法分析器、语义分析器、优化器和代码生成器等多个模块。如果每次都要让调用者直接与这些子系统交互,不仅复杂、容易出错,而且对用户也不友好。而实际上,许多操作是常用的、固定的组合,例如“编译整个程序”就总是涉及所有子模块的调用顺序。 很容易想到通过一个统一的入口,也就是新增一个“外观类”或“外观函数”,封装这些子系统的内部调用逻辑。这就是外观模式,对外提供一个简化接口,同时又保留了对细节的操控能力。 + +## 享元模式(Flyweight) + +在创建同一类的大量对象实例时,往往会面临内存占用过高的问题。这种情况的一个常见原因是:对象实例中包含了大量冗余的、可以共享的数据。例如,在游戏开发中,多个实体可能共用相同的模型和贴图资源。如果每个实例都独立持有这些资源,就会造成不必要的内存浪费。 + +为了解决这一问题,享元模式提供了一种有效的解决方案。它的核心思想是将对象的数据划分为可共享的和不可共享的。在实现过程中,享元模式通常通过一个享元工厂来统一管理和缓存内部状态。当需要创建新对象时,工厂会首先检查是否已有对应的内部状态资源,若有则复用,从而避免重复实例化共享部分,显著降低内存开销。