設計模式簡單代碼之Flyweight模式

來源:互聯網
上載者:User

歡迎轉載,請註明出處。

[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模式幫你節省了多少空間。謝謝!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.