C++設計模式-Flyweight享元模式

Flyweight享元模式ios

做用:運用共享技術有效地支持大量細粒度的對象。編輯器

內部狀態intrinsic和外部狀態extrinsic函數

1)Flyweight模式中,最重要的是將對象分解成intrinsic和extrinsic兩部分。

2)內部狀態:在享元對象內部而且不會隨環境改變而改變的共享部分,能夠稱爲是享元對象的內部狀態

3)外部狀態:而隨環境改變而改變的,取決於應用環境,或是實時數據,這些不能夠共享的東西就是外部狀態了。

4)內部狀態和外部狀態之間的區別:
  在Flyweight模式應用中,一般修改的是外部狀態屬性,而內部狀態屬性通常都是用於參考或計算時引用。
Flyweight執行時所需的狀態一定是內部的或外部的。內部狀態存儲於ConcreteFlyweight對象之中;而外部狀態則由Client對象存儲或計算。當用戶調用Flyweight對象的操做時,將該狀態傳遞給它。

以文字處理軟件爲例:字體

  內部狀態存儲於flyweight中,它包含了獨立於flyweight場景的信息,這些信息使得flyweight能夠被共享。如字符代碼,字符大小……this

  外部狀態取決於flyweight場景,並根據場景而變化,所以不可共享。用戶對象負責在必要的時候將外部狀態傳遞給flyweight,如字符位置,字符顏色……

UML圖:


解析
Flyweight:享元類的基類,定義一個接口,經過這個接口Flyweight能夠接受並做用於外部狀態。spa

ConcreteFlyweight:實現Flyweight接口, 併爲內部狀態( 若是有的話) 增長存儲空間。ConcreteFlyweight對象必須是可共享的。它所存儲的狀態必須是內部的(intrinsic);即,它必須獨立於ConcreteFlyweight對象的場景。設計

UnsharedConcreteFlyweight:並不是全部的Flyweight子類都須要被共享。Flyweight接口使共享成爲可能,但它並不強制共享。在Flyweight對象結構的某些層次,UnsharedConcreteFlyweight對象一般將ConcreteFlyweight對象做爲子節點。

FlyweightFactory3d

1) 建立並管理Flyweight對象。code

2)確保合理地共享Flyweight。當用戶請求一個Flyweight時,FlyweightFactory對象提供一個已建立的實例或者建立一個(若是不存在的話)

Client
1)維持一個對Flyweight的引用。對象

2)計算或存儲一個(多個)Flyweight的外部狀態。

分析
   享元模式能夠避免大量很是類似類的開銷。在程序設計中,有時須要生成大量細粒度的類實例來表示數據。若是能發現這些實例數據除了幾個參數外基本都是相同的。有時就可以大幅度地減小實例化的類的數量。若是能把那些參數移到類實例的外面,在方法調用時將它們傳遞進來,就能夠經過共享大幅度地減小單個實例的數目。

  好比在文檔編輯器的設計過程當中,咱們若是爲沒有字母建立一個對象的話,系統可能會由於大量的對象而形成存儲開銷的浪費。例如一個字母「a」在文檔中出現了100000次,而實際上咱們可讓這一萬個字母「a」共享一個對象,固然由於在不一樣的位置可能字母「a」有不一樣的顯示效果(例如字體和大小等設置不一樣),在這種狀況咱們能夠爲將對象的狀態分爲「外部狀態」和「內部狀態」,將能夠被共享(不會變化)的狀態做爲內部狀態存儲在對象中,而外部對象(例如上面提到的字體、大小等)咱們能夠在適當的時候將外部對象最爲參數傳遞給對象(例如在顯示的時候,將字體、大小等信息傳遞給對象)。

  Flyweight的內部狀態是用來共享的,Flyweightfactory負責維護一個Flyweight池(存放內部狀態的對象),當客戶端請求一個共享Flyweight時,這個factory首先搜索池中是否已經有可適用的,若是有,factory只是簡單返回送出這個對象,不然,建立一個新的對象,加入到池中,再返回送出這個對象.池爲重複或可共享的對象、屬性設置一個緩衝,稱爲內部狀態。這些內部狀態通常狀況下都是不可修改的,也就是在第一個對象、屬性被建立後,就不會去修改了(不然就沒意義了)。

  Flyweight 對對象的內部狀態進行共享,只爲每種內部狀態建立一個實例,對內部狀態使用了單例模式。

  用戶不該直接對ConcreteFlyweight類進行實例化,而只能從FlyweightFactory對象獲得ConcreteFlyweight對象,這能夠保證對它們適當地進行共享。

  存儲節約由如下幾個因素決定:
  1) 由於共享,實例總數減小的數目
  2) 對象內部狀態的平均數目
  3) 外部狀態是計算的仍是存儲的

實現要點
1)享元工廠維護一張享元實例表。

2)享元不可共享的狀態須要在外部維護。即刪除外部狀態:該模式的可用性在很大程度上取決因而否容易識別外部狀態並將它從共享對象中刪除。

3)按照需求能夠對享元角色進行抽象。

4)管理共享對象:引用計數和垃圾回收……

什麼時候採用
1)若是一個應用程序使用了大量的對象,而大量的這些對象形成了很大的存儲開銷時就應該考慮使用;

2)還有就是對象的大多數狀態可變爲外部狀態,若是刪除對象的外部狀態,那麼能夠用相對較少的共享對象取代不少組對象,此時能夠考慮所使用享元模式。

3)系統中有大量耗費了大量內存的細粒度對象,而且對外界來講這些對沒有任何差異的(或者說通過改造後能夠是沒有差異的)。

  在文檔編輯器例子中若是一個字符對應一個對象,那麼一篇文檔所要容納的對象將是很是的龐大耗費大量的內存。而實際組成文檔的字符是有限的,是由這些字符不一樣的組合和排列獲得的。因此須要共享,將基本的字符進行共享,將使得字符對象變得有限。

代碼以下:

Flyweight.h

 1 #ifndef _FLYWEIGHT_H_
 2 #define _FLYWEIGHT_H_
 3 
 4 #include <string>
 5 #include <vector>
 6 
 7 using namespace std;
 8 
 9 //基類,定義操做接口Operation
10 class Flyweight
11 {
12 public:
13     //操做外部狀態extrinsicState
14     virtual void Operation(const string& extrinsicState)=0;
15     string GetIntrinsicState();
16     virtual ~Flyweight();
17 protected:
18     Flyweight(string intrinsicState);
19 private:
20     //內部狀態,也能夠放在ConcreteFlyweight中
21     string _intrinsicState;
22 };
23 
24 class ConcreteFlyweight:public Flyweight
25 {
26 public:
27     //實現接口函數
28     virtual void Operation(const string& extrinsicState);
29     ConcreteFlyweight(string intrinsicState);
30     ~ConcreteFlyweight();
31 };
32 
33 class UnsharedConcreteFlyweight:public Flyweight
34 {
35 public:
36     virtual void Operation(const string& extrinsicState);
37     UnsharedConcreteFlyweight(string intrinsicState);
38     ~UnsharedConcreteFlyweight();
39 };
40 
41 class FlyweightFactory
42 {
43 public:
44     FlyweightFactory();
45     ~FlyweightFactory();
46     //得到一個請求的Flyweight對象
47     Flyweight* GetFlyweight(string key);
48     //獲取容器中存儲的對象數量
49     void GetFlyweightCount();
50 protected:
51 private:
52     //保存內部狀態對象的容器
53     vector<Flyweight*> m_vecFly;
54 };
55 #endif

Flyweight.cpp

 1 #include "Flyweight.h"
 2 #include <iostream>
 3 
 4 using namespace std;
 5 
 6 Flyweight::Flyweight(string intrinsicState)
 7 {
 8     this->_intrinsicState = intrinsicState;
 9 }
10 
11 Flyweight::~Flyweight()
12 {}
13 
14 string Flyweight::GetIntrinsicState()
15 {
16     return this->_intrinsicState;
17 }
18 
19 ConcreteFlyweight::ConcreteFlyweight(string intrinsicState):Flyweight(intrinsicState)
20 {
21 }
22 
23 ConcreteFlyweight::~ConcreteFlyweight()
24 {
25 }
26 
27 void ConcreteFlyweight::Operation(const string& extrinsicState)
28 {
29     cout << this->GetIntrinsicState() << endl;
30     cout << extrinsicState << endl;
31 }
32 
33 UnsharedConcreteFlyweight::UnsharedConcreteFlyweight(string intrinsicState):Flyweight(intrinsicState)
34 {
35 }
36 
37 UnsharedConcreteFlyweight::~UnsharedConcreteFlyweight()
38 {
39 }
40 
41 void UnsharedConcreteFlyweight::Operation(const string& extrinsicState)
42 {
43     cout << "extrinsicState" << endl;
44 }
45 
46 FlyweightFactory::FlyweightFactory()
47 {}
48 
49 FlyweightFactory::~FlyweightFactory()
50 {}
51 
52 //若該對象已存在,直接返回,不然新建一個對象,存入容器中,再返回
53 Flyweight* FlyweightFactory::GetFlyweight(string key)
54 {
55     vector<Flyweight*>::iterator iter = this->m_vecFly.begin();
56     for(;iter!= this->m_vecFly.end();iter++)
57     {
58         if((*iter)->GetIntrinsicState() == key)
59         {
60             return *iter;
61         }
62     }
63     Flyweight* fly = new ConcreteFlyweight(key);
64     this->m_vecFly.push_back(fly);
65     return fly;
66 }
67 
68 void FlyweightFactory::GetFlyweightCount()
69 {
70     cout << this->m_vecFly.size() << endl;
71 }

main.cpp

 1 #include "Flyweight.h"
 2 #include <iostream>
 3 #include <string>
 4 
 5 using namespace std;
 6 
 7 int main()
 8 {
 9     //外部狀態extrinsicState
10     string extrinsicState = "ext";
11 
12     //工廠對象,工廠對象
13     FlyweightFactory* fc = new FlyweightFactory();
14 
15     //向工廠申請一個Flyweight對象,且該對象的內部狀態值爲「hello」
16     Flyweight* fly = fc->GetFlyweight("hello");
17 
18     Flyweight* fly1 = fc->GetFlyweight("hello");
19 
20     //應用外部狀態
21     fly->Operation(extrinsicState);
22 
23     fc->GetFlyweightCount();
24 
25     return 0;
26 }

另一個文本處理的例子

參考:

http://www.dofactory.com/Patterns/PatternFlyweight.aspx

http://sourcemaking.com/design_patterns/flyweight/c%2523#

代碼以下:

Document.h

 1 #ifndef _DOCUMENT_H_
 2 #define _DOCUMENT_H_
 3 
 4 #include <string>
 5 #include <vector>
 6 
 7 using namespace std;
 8 
 9 // The 'Flyweight' abstract class
10 class character
11 {
12 public:
13     //析構函數
14     virtual ~character();
15     //應用外部狀態
16     virtual void Display(int width,int height,int ascent,int descent,int pointSize)=0;
17     //獲取內部狀態
18     virtual char GetSymbol()=0;
19 protected:
20     /*-----內部狀態---------*/
21     char symbol;
22     /*----------------------/
23 
24     /*-----外部狀態---------*/
25     int width;
26     int height;
27     int ascent;
28     int descent;
29     int pointSize;
30     /*----------------------*/
31     //構造函數
32     character(char c);
33 };
34 
35 //A 'ConcreteFlyweight' class
36 class characterA:public character
37 {
38 public:
39     characterA(char c);
40     ~characterA();
41     virtual void Display(int width,int height,int ascent,int descent,int pointSize);
42     virtual char GetSymbol();
43 protected:
44 private:
45 };
46 
47 //B 'ConcreteFlyweight' class
48 class characterB:public character
49 {
50 public:
51     characterB(char c);
52     ~characterB();
53     virtual void Display(int width,int height,int ascent,int descent,int pointSize);
54 protected:
55 private:
56 };
57 
58 //C 'ConcreteFlyweight' class
59 class characterC:public character
60 {
61 public:
62     characterC(char c);
63     ~characterC();
64     virtual void Display(int width,int height,int ascent,int descent,int pointSize);
65 protected:
66 private:
67 };
68 
69 //D 'ConcreteFlyweight' class
70 class characterD:public character
71 {
72 public:
73     characterD(char c);
74     ~characterD();
75     virtual void Display(int width,int height,int ascent,int descent,int pointSize);
76 protected:
77 private:
78 };
79 /*
80 ...
81 */
82 
83 //The 'FlyweightFactory' class
84 class characterFactory
85 {
86 public:
87     characterFactory();
88     ~characterFactory();
89     //申請一個character對象
90     character* GetCharacter(char);
91     //獲取存儲的character*數量
92     vector<character*>::size_type GetCount();
93 private:
94     //保存character*的容器,能夠換成List等其它容器
95     vector<character*> m_vecCharacter;
96 };
97 
98 #endif

Document.cpp

 1 #include "Document.h"
 2 #include <iostream>
 3 
 4 character::character(char c)
 5 {
 6     this->symbol = c;
 7 }
 8 
 9 character::~character()
10 {
11 }
12 
13 characterA::characterA(char c):character(c)
14 {
15 }
16 
17 characterA::~characterA()
18 {
19 }
20 
21 char characterA::GetSymbol()
22 {
23     return this->symbol;
24 }
25 
26 void characterA::Display(int width,int height,int ascent,int descent,int pointSize)
27 {
28     //接收並做用外部狀態
29     this->ascent = ascent;
30     this->descent = descent;
31     this->height = height;
32     this->pointSize = pointSize;
33     this->width = width;
34 
35     cout << this->symbol <<" "
36      << this->ascent <<" "
37      << this->descent <<" "
38      << this->height <<" "
39      << this->pointSize <<" "
40      << this->width << endl;
41 }
42 
43 characterFactory::characterFactory()
44 {}
45 
46 characterFactory::~characterFactory()
47 {}
48 
49 character* characterFactory::GetCharacter(char c)
50 {
51     vector<character*>::iterator iter = this->m_vecCharacter.begin();
52     for(;iter != this->m_vecCharacter.end();iter++)
53     {
54         if((*iter)->GetSymbol() == c)
55         {
56             return *iter;
57         }
58     }
59     character* pf = new characterA(c);
60     this->m_vecCharacter.push_back(pf);
61     return pf;
62 }
63 
64 vector<character*>::size_type characterFactory::GetCount()
65 {
66     return this->m_vecCharacter.size();
67 }

main.cpp

 1 #include "Flyweight.h"
 2 #include "Document.h"
 3 #include <iostream>
 4 #include <string>
 5 
 6 using namespace std;
 7 
 8 int main()
 9 {
10     //存儲外部狀態
11     int ascent = 70;
12     int descent = 0;
13     int height = 100;
14     int width = 120;
15     int pointSize = 10;
16 
17     string test = "AABCDDEFGHI";
18     string::iterator it = test.begin();
19     characterFactory* pcF = new characterFactory();
20     for(;it!=test.end();it++)
21     {
22         pointSize++;
23         char c = *it;
24         //申請一個character對象
25         character* charc= pcF->GetCharacter(c);
26         //應用外部狀態
27         charc->Display(width,height,ascent,descent,pointSize);
28     }
29     vector<character*>::size_type sizeChar = pcF->GetCount();
30     cout << "count:" << sizeChar << endl;
31 
32     return 0;
33 }
相關文章
相關標籤/搜索