程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> 關於C++ >> C++設計形式編程之Flyweight享元形式構造詳解

C++設計形式編程之Flyweight享元形式構造詳解

編輯:關於C++

C++設計形式編程之Flyweight享元形式構造詳解。本站提示廣大學習愛好者:(C++設計形式編程之Flyweight享元形式構造詳解)文章只能為提供參考,不一定能成為您想要的結果。以下是C++設計形式編程之Flyweight享元形式構造詳解正文


由碰到的成績引出享元形式:

在面向對象體系的設計何完成中,創立對象是最為罕見的操作。這外面就有一個成績:假如一個運用法式應用了太多的對象,就會形成很年夜的存儲開支。特殊是關於年夜量輕量級(細粒度)的對象,好比在文檔編纂器的設計進程中,我們假如為沒有字母創立一個對象的話,體系能夠會由於年夜量的對象而形成存儲開支的糟蹋。例如一個字母"a"在文檔中湧現了100000 次,而現實上我們可讓這一萬個字母"a"同享一個對象,固然由於在分歧的地位能夠字母"a"有分歧的顯示後果(例如字體和年夜小等設置分歧),在這類情形我們可認為將對象的狀況分為"內部狀況"和"外部狀況",將可以被同享(不會變更)的狀況作為外部狀況存儲在對象中,而內部對象(例如下面提到的字體、年夜小等)我們可以在恰當的時刻將內部對象最為參數傳遞給對象(例如在顯示的時刻,將字體、年夜小等信息傳遞給對象)。

感化:應用同享技巧有用地支撐年夜量細粒度的對象。

外部狀況intrinsic和內部狀況extrinsic:

1)Flyweight形式中,最主要的是將對象分化成intrinsic和extrinsic兩部門。

2)外部狀況:在享元對象外部而且不會隨情況轉變而轉變的同享部門,可以稱為是享元對象的外部狀況

3)內部狀況:而隨情況轉變而轉變的,取決於運用情況,或是及時數據,這些弗成以同享的器械就是內部狀況了。

4)外部狀況和內部狀況之間的差別:
  在Flyweight形式運用中,平日修正的是內部狀況屬性,而外部狀況屬性普通都是用於參考或盤算時援用。
Flyweight履行時所需的狀況一定是外部的或內部的。外部狀況存儲於ConcreteFlyweight對象當中;而內部狀況則由Client對象存儲或盤算。當用戶挪用Flyweight對象的操作時,將該狀況傳遞給它。

以文字處置軟件為例:

  外部狀況存儲於flyweight中,它包括了自力於flyweight場景的信息,這些信息使得flyweight可以被同享。如字符代碼,字符年夜小……

  內部狀況取決於flyweight場景,並依據場景而變更,是以弗成同享。用戶對象擔任在需要的時刻將內部狀況傳遞給flyweight,如字符地位,字符色彩……

UML圖:

解析:
Flyweight:享元類的基類,界說一個接口,經由過程這個接口Flyweight可以接收並感化於內部狀況。

ConcreteFlyweight:完成Flyweight接口, 並為外部狀況( 假如有的話) 增長存儲空間。ConcreteFlyweight對象必需是可同享的。它所存儲的狀況必需是外部的(intrinsic);即,它必需自力於ConcreteFlyweight對象的場景。

UnsharedConcreteFlyweight:並不是一切的Flyweight子類都須要被同享。Flyweight接口使同享成為能夠,但它其實不強迫同享。在Flyweight對象構造的某些條理,UnsharedConcreteFlyweight對象平日將ConcreteFlyweight對象作為子節點。

FlyweightFactory:

1) 創立並治理Flyweight對象。

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)體系中有年夜量消耗了年夜量內存的細粒度對象,而且對外界來講這些對沒有任何差異的(或許說經由改革後可所以沒有差異的)。

  在文檔編纂器例子中假如一個字符對應一個對象,那末一篇文檔所要包容的對象將長短常的宏大消耗年夜量的內存。而現實構成文檔的字符是無限的,是由這些字符分歧的組合和分列獲得的。所以須要同享,將根本的字符停止同享,將使得字符對象變得無限。

示例:
享元形式在編纂器體系中年夜量應用。一個文本編纂器常常會供給許多種字體,而平日的做法就是將每個字母做成一個享元對象。享元對象的內蘊狀況就是這個字母,而字母在文本中的地位和字模作風等其他信息則是外蘊狀況。好比,字母a能夠湧現在文本的許多處所,固然這些字母a的地位和字模作風分歧,然則一切這些處所應用的都是統一個字母對象。如許一來,字母對象便可以在全部體系中同享。

// Flyweight pattern -- Real World example 


using System;
using System.Collections;

namespace DoFactory.GangOfFour.Flyweight.RealWorld
{

 // MainApp test application 

 class MainApp
 {
  static void Main()
  {
   // Build a document with text 
   string document = "AAZZBBZB";
   char[] chars = document.ToCharArray();

   CharacterFactory f = new CharacterFactory();

   // extrinsic state 
   int pointSize = 10;

   // For each character use a flyweight object 
   foreach (char c in chars)
   {
    pointSize++;
    Character character = f.GetCharacter(c);
    character.Display(pointSize);
   }

   // Wait for user 
   Console.Read();
  }
 }

 // "FlyweightFactory" 

 class CharacterFactory
 {
  private Hashtable characters = new Hashtable();

  public Character GetCharacter(char key)
  {
   // Uses "lazy initialization" 
   Character character = characters[key] as Character;
   if (character == null)
   {
    switch (key)
    {
     case 'A': character = new CharacterA(); break;
     case 'B': character = new CharacterB(); break;
      // 
     case 'Z': character = new CharacterZ(); break;
    }
    characters.Add(key, character);
   }
   return character;
  }
 }

 // "Flyweight" 

 abstract class Character
 {
  protected char symbol;
  protected int width;
  protected int height;
  protected int ascent;
  protected int descent;
  protected int pointSize;

  public abstract void Display(int pointSize);
 }

 // "ConcreteFlyweight" 

 class CharacterA : Character
 {
  // Constructor 
  public CharacterA()
  {
   this.symbol = 'A';
   this.height = 100;
   this.width = 120;
   this.ascent = 70;
   this.descent = 0;
  }

  public override void Display(int pointSize)
  {
   this.pointSize = pointSize;
   Console.WriteLine(this.symbol + 
    " (pointsize " + this.pointSize + ")");
  }
 }

 // "ConcreteFlyweight" 

 class CharacterB : Character
 {
  // Constructor 
  public CharacterB()
  {
   this.symbol = 'B';
   this.height = 100;
   this.width = 140;
   this.ascent = 72;
   this.descent = 0;
  }

  public override void Display(int pointSize)
  {
   this.pointSize = pointSize;
   Console.WriteLine(this.symbol + 
    " (pointsize " + this.pointSize + ")");
  }

 }

 // C, D, E, etc. 

 // "ConcreteFlyweight" 

 class CharacterZ : Character
 {
  // Constructor 
  public CharacterZ()
  {
   this.symbol = 'Z';
   this.height = 100;
   this.width = 100;
   this.ascent = 68;
   this.descent = 0;
  }

  public override void Display(int pointSize)
  {
   this.pointSize = pointSize;
   Console.WriteLine(this.symbol + 
    " (pointsize " + this.pointSize + ")");
  }
 }
}

Output:

享元形式的長處和缺陷

享元形式的長處在於它年夜幅度地下降內存中對象的數目。然則,它做到這一點所支付的價值也是很高的:
享元形式使得體系加倍龐雜。為了使對象可以同享,須要將一些狀況內部化,這使得法式的邏輯龐雜化。
享元形式將享元對象的狀況內部化,而讀取內部狀況使得運轉時光略微變長。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved