您的位置:首页 > 编程语言

设计模式简单代码之Flyweight模式

2014-01-27 14:57 316 查看
出自: /article/8353499.html

欢迎转载,请注明出处。

[Flyweight模式]

官方描述:

意图

运用共享技术有效地支持大量细粒度的对象。

适用性

1、一个应用程序使用了大量的对象。

2、完全由于使用大量的对象,造成很大的存储开销。

3、对象的大多数状态都可变为外部状态。

4、如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象。

5、应用程序不依赖于对象标识。由于Flyweight 对象可以被共享,对于概念上明显有别的对象,标识测试将返回真值。

我的描述:

在开始设计类的时候,很自然的根据现实情况把某些属性作为类的一部分,例如设计一个图书的管理系统,每本书都有出版社、编号、作者、价钱等的属性,所以这个书的类可以这样设计:

class Book

{

public:

string GetPublish() {return m_publishCompany;}

string GetWriter() {return m_writer;}

int GetBookID() {return m_bookID;}

int GetPrice() {return m_price;}

string GetName() {return m_name;}

void SetPublish(string &s) {m_publishCompany = s;}

void SetWriter(string &s) {m_writer = s;}

void SetBookID(int id) {m_bookID = id;}

void SetPrice(int price) {m_price = price;}

void SetName(string &s) {m_name = s;}

private:

string m_publishCompany; // 出版社

string m_writer; // 作者

int m_bookID; // 书籍编号

int m_price; // 价钱

string m_name; // 书名

};

这非常自然。但是随着系统的开发和试运行,这种设计就表现出一些不足的地方了,例如一般图书会非常多,成千上万本,在这些书中可能会有相同的出版社或者相同的作者,那对每本书来说就会重复了,也就是浪费了一些重复的空间。

如果每本书都耗费一些空间,那整个软件系统所耗费的空间是不可想象的。所以,我们就要想办法来解决这个问题。

高明的面向对象设计者就想出了这个办法,把一些相同的属性(把它叫做“享元”)提取出来,并用一个表来管理(池),这就是Flyweight模式的思想所在。好了,我们现在来看看示意图:



这里的ConcreteFlyweight就是需要共享的属性(享元),例如上面的出版社和作者,这里的UnsharedConcreteFlyweight就是

不用共享的属性(书籍编号和价钱)。

想象一下系统里面Book类的使用:

1、先看看不用共享模式:

Book book1, book2, book3;

book1.SetPublish("机械工业出版社");

book1.SetWriter("候捷");

book1.SetBookID(0000);

book1.SetPrice(20);

book1.SetName("C++好野");

book2.SetPublish("人民邮电出版社");

book2.SetWriter("候捷");

book2.SetBookID(0001);

book2.SetPrice(30);

book2.SetName("C++是好劲");

book3.SetPublish("机械工业出版社");

book3.SetWriter("一雨田");

book3.SetBookID(0002);

book3.SetPrice(50);

book3.SetName("C++无得顶,我是铁头功...");

这里有两个“机械工业出版社”和两个“候捷”,重复了。如果使用共享模式的话,这里的浪费就可以避免了。

别看这里只有两个,想象一下成千上万本书时的空间浪费...

2、使用共享模式,把出版社和作者两个属性作为享元(Fly~~Weight)

PublishFlyweightFactory pff;

WriterFlyweightFactory wff;

Book book1, book2, book3;

book1.SetPublish(pff.GetPublish("机械工业出版社")->GetName());

book1.SetWriter(wff.GetWriter("候捷")->GetName());

book1.SetBookID(0000);

book1.SetPrice(20);

book1.SetName("C++好野");

book2.SetPublish(pff.GetPublish("人民邮电出版社")->GetName());

book2.SetWriter(wff.GetWriter("候捷")->GetName());

book2.SetBookID(0001);

book2.SetPrice(30);

book2.SetName("C++是好劲");

book3.SetPublish(pff.GetPublish("机械工业出版社")->GetName());

book3.SetWriter(wff.GetWriter("一雨田")->GetName());

book3.SetBookID(0002);

book3.SetPrice(50);

book3.SetName("C++无得顶,我是铁头功...");

为什么使用了PublishFlyweightFactory和WriterFlyweightFactory之后就可以节省空间了呢?

奥妙就在于GetPublish和GetWriter的实现:

PublishFlyweight* GetPublish(string key)

{

PublishFlyweight *p;

mapPublish::iterator it;

it = mapPublish.find(key);

// 存在这个Writer

if(it != mapPublish.end() )

p = it;

else

{// 插入这个PublishFlyweight

p = new PublishFlyweight(key);

mapPublish[key] = p;

}

return p;

}

GetWriter的实现大同小异,这里就不列出来了,请看详细代码里的实现。

下面是完整的代码,可以在一个CPP文件里编译使用,由于使用CSDN提供的插入代码功能会使得整段拷贝有点问题,所以这里还是直接给出代码,并标注颜色,方便大家的拷贝:

// Flyweight.cpp

#pragma warning(disable: 4786)

#include <iostream>

#include <map>

#include <string>

using namespace std;

class Book

{

public:

string GetPublish() {return *m_publishCompany;}

string GetWriter() {return *m_writer;}

int GetBookID() {return m_bookID;}

int GetPrice() {return m_price;}

string GetName() {return m_name;}

void SetPublish(string *s) {m_publishCompany = s;}

void SetWriter(string *s) {m_writer = s;}

void SetBookID(int id) {m_bookID = id;}

void SetPrice(int price) {m_price = price;}

void SetName(string &s) {m_name = s;}

private:

string *m_publishCompany; // 出版社

string *m_writer; // 作者

int m_bookID; // 书籍编号

int m_price; // 价钱

string m_name; // 书名

};

class PublishFlyweight

{

public:

PublishFlyweight(string s)

{

m_name = s;

}

string GetName()

{

return m_name;

}

private:

string m_name;

};

class PublishFlyweightFactory

{

public:

PublishFlyweight* GetPublish(string key)

{

PublishFlyweight *p;

map<string, PublishFlyweight*>::iterator it;

it = mapPublish.find(key);

// 存在这个出版社

if(it != mapPublish.end() )

{

// 这里可能有点难懂,请查阅STL的帮助文档

// 其实second就是指 map<string, PublishFlyweight*> 的 PublishFlyweight*

p = (*it).second;

cout << "已经有这个出版社: " << p->GetName() << " 你节省了" << strlen(p->GetName().c_str()) << "字节的空间" << endl;

}

else

{// 插入这个PublishFlyweight

p = new PublishFlyweight(key);

mapPublish[key] = p;

}

return p;

}

private:

map<string, PublishFlyweight*> mapPublish;

};

class WriterFlyweight

{

public:

WriterFlyweight(string s)

{

m_name = s;

}

string GetName()

{

return m_name;

}

private:

string m_name;

};

class WriterFlyweightFactory

{

public:

WriterFlyweight* GetWriter(string key)

{

WriterFlyweight *p;

map<string, WriterFlyweight*>::iterator it;

it = mapWriter.find(key);

// 存在这个Writer

if(it != mapWriter.end() )

{

// 这里可能有点难懂,请查阅STL的帮助文档

// 其实second就是指 map<string, WriterFlyweight*> 的 WriterFlyweight*

p = (*it).second;

cout << "已经有这个作者名字: " << p->GetName() << " 你节省了" << strlen(p->GetName().c_str()) << "字节的空间" << endl;

}

else

{// 插入这个PublishFlyweight

p = new WriterFlyweight(key);

mapWriter[key] = p;

}

return p;

}

private:

map<string, WriterFlyweight*> mapWriter;

};

void ShowBookInfo(Book book)

{

cout << "书名:" << book.GetName() << endl;

cout << "编号:" << book.GetBookID() << endl;

cout << "价钱:" << book.GetPrice() << endl;

cout << "出版:" << book.GetPublish() << endl;

cout << "作者:" << book.GetWriter() << endl;

cout << endl;

}

void main()

{

PublishFlyweightFactory pff;

WriterFlyweightFactory wff;

Book book1, book2, book3;

book1.SetPublish( &(pff.GetPublish("机械工业出版社")->GetName()) );

book1.SetWriter( &(wff.GetWriter("候捷")->GetName()) );

book1.SetBookID(0000);

book1.SetPrice(20);

book1.SetName(string("<<C++好野>>"));

ShowBookInfo(book1);

book2.SetPublish( &(pff.GetPublish("人民邮电出版社")->GetName()) );

book2.SetWriter( &(wff.GetWriter("候捷")->GetName()) );

book2.SetBookID(0001);

book2.SetPrice(30);

book2.SetName(string("<<C++是好劲>>"));

ShowBookInfo(book2);

book3.SetPublish( &(pff.GetPublish("机械工业出版社")->GetName()) );

book3.SetWriter( &(wff.GetWriter("一雨田")->GetName()) );

book3.SetBookID(0002);

book3.SetPrice(50);

book3.SetName(string("<<C++无得顶,我是铁头功...>>"));

ShowBookInfo(book3);

}

好了,如果你能看到这里,希望能帮助你把Flyweight模式理解了,但最好还是动手把代码拷贝到VC 里,编译运行一下,你可以看到Flyweight模式帮你节省了多少空间。谢谢!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: