溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何理解Flyweight模式

發(fā)布時間:2021-10-14 10:08:18 來源:億速云 閱讀:145 作者:柒染 欄目:編程語言

這篇文章將為大家詳細講解有關如何理解Flyweight模式,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。

[Flyweight模式]

  
官方描述:

意圖
 運用共享技術有效地支持大量細粒度的對象。

適用性 
 1、一個應用程序使用了大量的對象。 
 2、完全由于使用大量的對象,造成很大的存儲開銷。 
 3、對象的大多數(shù)狀態(tài)都可變?yōu)橥獠繝顟B(tài)。 
 4、如果刪除對象的外部狀態(tài),那么可以用相對較少的共享對象取代很多組對象。 
 5、應用程序不依賴于對象標識。由于Flyweight 對象可以被共享,對于概念上明顯有別的對象,標識測試將返回真值。


我的描述:

 在開始設計類的時候,很自然的根據(jù)現(xiàn)實情況把某些屬性作為類的一部分,例如設計一個圖書的管理系統(tǒng),每本書都有出版社、編號、作者、價錢等的屬性,所以這個書的類可以這樣設計:

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;    // 書名
};

 這非常自然。但是隨著系統(tǒng)的開發(fā)和試運行,這種設計就表現(xiàn)出一些不足的地方了,例如一般圖書會非常多,成千上萬本,在這些書中可能會有相同的出版社或者相同的作者,那對每本書來說就會重復了,也就是浪費了一些重復的空間。
如果每本書都耗費一些空間,那整個軟件系統(tǒng)所耗費的空間是不可想象的。所以,我們就要想辦法來解決這個問題。
 高明的面向?qū)ο笤O計者就想出了這個辦法,把一些相同的屬性(把它叫做“享元”)提取出來,并用一個表來管理(池),這就是Flyweight模式的思想所在。好了,我們現(xiàn)在來看看示意圖:

如何理解Flyweight模式
 

 
 這里的ConcreteFlyweight就是需要共享的屬性(享元),例如上面的出版社和作者,這里的UnsharedConcreteFlyweight就是
不用共享的屬性(書籍編號和價錢)。

    想象一下系統(tǒng)里面Book類的使用:
 1、先看看不用共享模式:
 
 Book book1, book2, book3;
 book1.SetPublish("機械工業(yè)出版社");
 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("機械工業(yè)出版社");
 book3.SetWriter("一雨田");
 book3.SetBookID(0002);
 book3.SetPrice(50);
 book3.SetName("C++無得頂,我是鐵頭功..."); 
 
 這里有兩個“機械工業(yè)出版社”和兩個“候捷”,重復了。如果使用共享模式的話,這里的浪費就可以避免了。
 別看這里只有兩個,想象一下成千上萬本書時的空間浪費...

 2、使用共享模式,把出版社和作者兩個屬性作為享元(Fly~~Weight)
 PublishFlyweightFactory pff;
 WriterFlyweightFactory wff;
 Book book1, book2, book3;

 book1.SetPublish(pff.GetPublish("機械工業(yè)出版社")->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("機械工業(yè)出版社")->GetName());
 book3.SetWriter(wff.GetWriter("一雨田")->GetName());
 book3.SetBookID(0002);
 book3.SetPrice(50);
 book3.SetName("C++無得頂,我是鐵頭功...");

 為什么使用了PublishFlyweightFactory和WriterFlyweightFactory之后就可以節(jié)省空間了呢?

 奧妙就在于GetPublish和GetWriter的實現(xiàn):
 
 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的實現(xiàn)大同小異,這里就不列出來了,請看詳細代碼里的實現(xiàn)。 

下面是完整的代碼,可以在一個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 << "已經(jīng)有這個出版社: " << p->GetName() << " 你節(jié)省了" << strlen(p->GetName().c_str()) << "字節(jié)的空間" << 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 << "已經(jīng)有這個作者名字: " << p->GetName() << " 你節(jié)省了" << strlen(p->GetName().c_str()) << "字節(jié)的空間" << 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("機械工業(yè)出版社")->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("機械工業(yè)出版社")->GetName()) );
 book3.SetWriter( &(wff.GetWriter("一雨田")->GetName()) );
 book3.SetBookID(0002);
 book3.SetPrice(50);
 book3.SetName(string("<<C++無得頂,我是鐵頭功...>>"));
 
 ShowBookInfo(book3);
}

好了,如果你能看到這里,希望能幫助你把Flyweight模式理解了,但最好還是動手把代碼拷貝到VC 里,編譯運行一下,你可以看到Flyweight模式幫你節(jié)省了多少空間。謝謝!

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權內(nèi)容。

AI