享元模式
设计模式
Flyweight模式也叫享元模式,是构造型模式之一,它通过与其他类似对象共享数据来减小内存占用。
在面向对象系统的设计和实现中,创建对象是最为常见的操作。这里面就有一个问题:如果一个应用程序使用了太多的对象,就会造成很大的存储开销。特别是对于大量轻量级(细粒度)的对象,比如在文档编辑器的设计过程中,我们如果没有为字母创建一个对象的话,系统可能会因为大量的对象而造成存储开销的浪费。例如一个字母“a”在文档中出现了10000次,而实际上我们可以让这一万个字母“a”共享一个对象,当然因为在不同的位置可能字母“a”有不同的显示效果(例如字体和大小等设置不同),在这种情况我们可以为将对象的状态分为“外部状态”和“内部状态”,将可以被共享(不会变化)的状态作为内部状态存储在对象中,而外部对象(例如上面提到的字体、大小等)我们可以在适当的时候将外部对象最为参数传递给对象(例如在显示的时候,将字体、大小等信息传递给对象)。
其中,Flyweight是抽象享元角色。它是产品的抽象类,同时定义出对象的外部状态和内部状态(外部状态及内部状态相关内容见后方)的接口或实现;
ConcreteFlyweight是具体享元角色,是具体的产品类,实现抽象角色定义的业务;
UnsharedConcreteFlyweight是不可共享的享元角色,一般不会出现在享元工厂中;
FlyweightFactory是享元工厂,它用于构造一个池容器,同时提供从池中获得对象的方法。
使用场景:
以共享的方式,支持大量的细粒度的对象。
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
| #include <iostream> #include <string> #include <map>
using namespace std;
class Person { public: Person(string name, int age) : m_name(name), m_age(age){}; ~Person() {
}; virtual void prinT() = 0; protected: string m_name; int m_age; };
class Teacher : public Person { public: Teacher(string name, int age, string id) : Person(name, age), m_id(id){}; ~Teacher();
void prinT() { cout << "name:" << m_name << " age:" << m_age << " id:" << m_id << endl; } protected: private: string m_id; };
class FlyWeightTeacherFactory { public: FlyWeightTeacherFactory() { m_map.clear(); }; ~FlyWeightTeacherFactory() { while(!m_map.empty()) { Person* tmp = NULL; auto it = m_map.begin(); tmp = it->second; m_map.erase(it); delete tmp; } }; Person* getTeacher(string id) { Person* tmp = NULL; map<string, Person*>::iterator it; it = m_map.find(id); if(it == m_map.end()) { string name = ""; int age = 0; cout << "\n请输入老师姓名 年龄:" << endl; cin >> name >> age; tmp = new Teacher(name, age, id); m_map.insert(pair<string, Person*>(id,tmp)); } else { tmp = it->second; } return tmp; } protected: private: map<string, Person*> m_map; };
int main() { Person* p1 = NULL; Person* p2 = NULL; FlyWeightTeacherFactory* fwtf = new FlyWeightTeacherFactory; p1 = fwtf->getTeacher("001"); p1->prinT(); p2 = fwtf->getTeacher("001"); p2->prinT(); cout << "p1:" << p1 << " p2:" << p2 << endl; cout << "Hello world!" << endl; return 0; }
|
输入:
输出:
1 2 3 4 5 6
| 请输入老师姓名 年龄: asd 12 name:asd age:12 id:001 name:asd age:12 id:001 p1:0xc8a650 p2:0xc8a650 Hello world!
|
第二条直接打印出来,说明两次获取的是同一个对象,即p1和p2是同一个对象。后续地址也是相同的。