欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
.NET設計模式(13):享元模式(Flyweight Pattern)

享元模式(Flyweight Pattern

——.NET設計模式系列之十三

Terrylee,20063

摘要:面向對象的思想很好地解決了抽象性的問(wèn)題,一般也不會(huì )出現性能上的問(wèn)題。但是在某些情況下,對象的數量可能會(huì )太多,從而導致了運行時(shí)的代價(jià)。那么我們如何去避免大量細粒度的對象,同時(shí)又不影響客戶(hù)程序使用面向對象的方式進(jìn)行操作?

本文試圖通過(guò)一個(gè)簡(jiǎn)單的字符處理的例子,運用重構的手段,一步步帶你走進(jìn)Flyweight模式,在這個(gè)過(guò)程中我們一同思考、探索、權衡,通過(guò)比較而得出好的實(shí)現方式,而不是給你最終的一個(gè)完美解決方案。

主要內容:

1.  Flyweight模式解說(shuō)

2.NET中的Flyweight模式

3Flyweight模式的實(shí)現要點(diǎn)

……

概述

面向對象的思想很好地解決了抽象性的問(wèn)題,一般也不會(huì )出現性能上的問(wèn)題。但是在某些情況下,對象的數量可能會(huì )太多,從而導致了運行時(shí)的代價(jià)。那么我們如何去避免大量細粒度的對象,同時(shí)又不影響客戶(hù)程序使用面向對象的方式進(jìn)行操作?

意圖

運用共享技術(shù)有效地支持大量細粒度的對象。[GOF 《設計模式》]

結構圖

1  Flyweight模式結構圖

生活中的例子

享元模式使用共享技術(shù)有效地支持大量細粒度的對象。公共交換電話(huà)網(wǎng)(PSTN)是享元的一個(gè)例子。有一些資源例如撥號音發(fā)生器、振鈴發(fā)生器和撥號接收器是必須由所有用戶(hù)共享的。當一個(gè)用戶(hù)拿起聽(tīng)筒打電話(huà)時(shí),他不需要知道使用了多少資源。對于用戶(hù)而言所有的事情就是有撥號音,撥打號碼,撥通電話(huà)。

使用撥號音發(fā)生器例子的享元模式對象圖

Flyweight模式解說(shuō)

Flyweight在拳擊比賽中指最輕量級,即“蠅量級”,這里翻譯為“享元”,可以理解為共享元對象(細粒度對象)的意思。提到Flyweight模式都會(huì )一般都會(huì )用編輯器例子來(lái)說(shuō)明,這里也不例外,但我會(huì )嘗試著(zhù)通過(guò)重構來(lái)看待Flyweight模式??紤]這樣一個(gè)字處理軟件,它需要處理的對象可能有單個(gè)的字符,由字符組成的段落以及整篇文檔,根據面向對象的設計思想和Composite模式,不管是字符還是段落,文檔都應該作為單個(gè)的對象去看待,這里只考慮單個(gè)的字符,不考慮段落及文檔等對象,于是可以很容易的得到下面的結構圖:

3

示意性實(shí)現代碼:

// "Charactor"
public abstract class Charactor
{
    
//Fields
    protected char _symbol;

    
protected int _width;

    
protected int _height;

    
protected int _ascent;

    
protected int _descent;

    
protected int _pointSize;

    
//Method
    public abstract void Display();
}


// "CharactorA"
public class CharactorA : Charactor

    
// Constructor 
    public CharactorA()
    
{
      
this._symbol = 'A';
      
this._height = 100;
      
this._width = 120;
      
this._ascent = 70;
      
this._descent = 0;
      
this._pointSize = 12;
    }


    
//Method
    public override void Display()
    
{
        Console.WriteLine(
this._symbol);
    }

}


// "CharactorB"
public class CharactorB : Charactor
{
    
// Constructor 
    public CharactorB()
    
{
        
this._symbol = 'B';
        
this._height = 100;
        
this._width = 140;
        
this._ascent = 72;
        
this._descent = 0;
        
this._pointSize = 10;
    }


    
//Method
    public override void Display()
    
{
        Console.WriteLine(
this._symbol);
    }

}


// "CharactorC"
public class CharactorC : Charactor
{
    
// Constructor 
    public CharactorC()
    
{
        
this._symbol = 'C';
        
this._height = 100;
        
this._width = 160;
        
this._ascent = 74;
        
this._descent = 0;
        
this._pointSize = 14;
    }


    
//Method
    public override void Display()
    
{
        Console.WriteLine(
this._symbol);
    }

}


好了,現在看到的這段代碼可以說(shuō)是很好地符合了面向對象的思想,但是同時(shí)我們也為此付出了沉重的代價(jià),那就是性能上的開(kāi)銷(xiāo),可以想象,在一篇文檔中,字符的數量遠不止幾百個(gè)這么簡(jiǎn)單,可能上千上萬(wàn),內存中就同時(shí)存在了上千上萬(wàn)個(gè)Charactor對象,這樣的內存開(kāi)銷(xiāo)是可想而知的。進(jìn)一步分析可以發(fā)現,雖然我們需要的Charactor實(shí)例非常多,這些實(shí)例之間只不過(guò)是狀態(tài)不同而已,也就是說(shuō)這些實(shí)例的狀態(tài)數量是很少的。所以我們并不需要這么多的獨立的Charactor實(shí)例,而只需要為每一種Charactor狀態(tài)創(chuàng )建一個(gè)實(shí)例,讓整個(gè)字符處理軟件共享這些實(shí)例就可以了??催@樣一幅示意圖:

4

現在我們看到的A,B,C三個(gè)字符是共享的,也就是說(shuō)如果文檔中任何地方需要這三個(gè)字符,只需要使用共享的這三個(gè)實(shí)例就可以了。然而我們發(fā)現單純的這樣共享也是有問(wèn)題的。雖然文檔中的用到了很多的A字符,雖然字符的symbol是相同的,它可以共享;但是它們的pointSize卻是不相同的,即字符在文檔中中的大小是不相同的,這個(gè)狀態(tài)不可以共享。為解決這個(gè)問(wèn)題,首先我們將不可共享的狀態(tài)從類(lèi)里面剔除出去,即去掉pointSize個(gè)狀態(tài)(只是暫時(shí)的J),類(lèi)結構圖如下所示:

5

示意性實(shí)現代碼:

// "Charactor"
public abstract class Charactor
{
    
//Fields
    protected char _symbol;

    
protected int _width;

    
protected int _height;

    
protected int _ascent;

    
protected int _descent;

    
//Method
    public abstract void Display();
}


// "CharactorA"
public class CharactorA : Charactor
{
    
// Constructor 
    public CharactorA()
    
{
        
this._symbol = 'A';
        
this._height = 100;
        
this._width = 120;
        
this._ascent = 70;
        
this._descent = 0;
    }


    
//Method
    public override void Display()
    
{
        Console.WriteLine(
this._symbol);
    }

}


// "CharactorB"
public class CharactorB : Charactor
{
    
// Constructor 
    public CharactorB()
    
{
        
this._symbol = 'B';
        
this._height = 100;
        
this._width = 140;
        
this._ascent = 72;
        
this._descent = 0;
    }


    
//Method
    public override void Display()
    
{
        Console.WriteLine(
this._symbol);
    }

}


// "CharactorC"
public class CharactorC : Charactor
{
    
// Constructor 
    public CharactorC()
    
{
        
this._symbol = 'C';
        
this._height = 100;
        
this._width = 160;
        
this._ascent = 74;
        
this._descent = 0;
    }


    
//Method
    public override void Display()
    
{
        Console.WriteLine(
this._symbol);
    }

}


好,現在類(lèi)里面剩下的狀態(tài)都可以共享了,下面我們要做的工作就是控制Charactor類(lèi)的創(chuàng )建過(guò)程,即如果已經(jīng)存在了“A”字符這樣的實(shí)例,就不需要再創(chuàng )建,直接返回實(shí)例;如果沒(méi)有,則創(chuàng )建一個(gè)新的實(shí)例。如果把這項工作交給Charactor類(lèi),即Charactor類(lèi)在負責它自身職責的同時(shí)也要負責管理Charactor實(shí)例的管理工作,這在一定程度上有可能違背類(lèi)的單一職責原則,因此,需要一個(gè)單獨的類(lèi)來(lái)做這項工作,引入CharactorFactory類(lèi),結構圖如下:

6

示意性實(shí)現代碼:

// "CharactorFactory"
public class CharactorFactory
{
    
// Fields
    private Hashtable charactors = new Hashtable();

    
// Constructor 
    public CharactorFactory()
    
{
        charactors.Add(
"A"new CharactorA());
        charactors.Add(
"B"new CharactorB());
        charactors.Add(
"C"new CharactorC());
    }

       
    
// Method
    public Charactor GetCharactor(string key)
    
{
        Charactor charactor 
= charactors[key] as Charactor;

        
if (charactor == null)
        
{
            
switch (key)
            
{
                
case "A": charactor = new CharactorA(); break;
                
case "B": charactor = new CharactorB(); break
                
case "C": charactor = new CharactorC(); break;
                
//

            }

            charactors.Add(key, charactor);
        }

        
return charactor;
    }

}


到這里已經(jīng)完全解決了可以共享的狀態(tài)(這里很丑陋的一個(gè)地方是出現了switch語(yǔ)句,但這可以通過(guò)別的辦法消除,為了簡(jiǎn)單期間我們先保持這種寫(xiě)法)。下面的工作就是處理剛才被我們剔除出去的那些不可共享的狀態(tài),因為雖然將那些狀態(tài)移除了,但是Charactor對象仍然需要這些狀態(tài),被我們剝離后這些對象根本就無(wú)法工作,所以需要將這些狀態(tài)外部化。首先會(huì )想到一種比較簡(jiǎn)單的解決方案就是對于不能共享的那些狀態(tài),不需要去在Charactor類(lèi)中設置,而直接在客戶(hù)程序代碼中進(jìn)行設置,類(lèi)結構圖如下:

7

示意性實(shí)現代碼:

public class Program
{
    
public static void Main()
    
{
        Charactor ca 
= new CharactorA();
        Charactor cb 
= new CharactorB();
        Charactor cc 
= new CharactorC();

        
//顯示字符

        
//設置字符的大小ChangeSize();
    }


    
public void ChangeSize()
    
{
        
//在這里設置字符的大小
    }

}


按照這樣的實(shí)現思路,可以發(fā)現如果有多個(gè)客戶(hù)端程序使用的話(huà),會(huì )出現大量的重復性的邏輯,用重構的術(shù)語(yǔ)來(lái)說(shuō)是出現了代碼的壞味道,不利于代碼的復用和維護;另外把這些狀態(tài)和行為移到客戶(hù)程序里面破壞了封裝性的原則。再次轉變我們的實(shí)現思路,可以確定的是這些狀態(tài)仍然屬于Charactor對象,所以它還是應該出現在Charactor類(lèi)中,對于不同的狀態(tài)可以采取在客戶(hù)程序中通過(guò)參數化的方式傳入。類(lèi)結構圖如下:

8

示意性實(shí)現代碼:

// "Charactor"
public abstract class Charactor
{
    
//Fields
    protected char _symbol;

    
protected int _width;

    
protected int _height;

    
protected int _ascent;

    
protected int _descent;

    
protected int _pointSize;

    
//Method
    public abstract void SetPointSize(int size);
    
public abstract void Display();
}


// "CharactorA"
public class CharactorA : Charactor
{
    
// Constructor 
    public CharactorA()
    
{
        
this._symbol = 'A';
        
this._height = 100;
        
this._width = 120;
        
this._ascent = 70;
        
this._descent = 0;
    }


    
//Method
    public override void SetPointSize(int size)
    
{
        
this._pointSize = size;
    }


    
public override void Display()
    
{
        Console.WriteLine(
this._symbol +
          
"pointsize:" + this._pointSize);
    }

}


// "CharactorB"
public class CharactorB : Charactor
{
    
// Constructor 
    public CharactorB()
    
{
        
this._symbol = 'B';
        
this._height = 100;
        
this._width = 140;
        
this._ascent = 72;
        
this._descent = 0;
    }


    
//Method
    public override void SetPointSize(int size)
    
{
        
this._pointSize = size;
    }


    
public override void Display()
    
{
        Console.WriteLine(
this._symbol +
          
"pointsize:" + this._pointSize);
    }

}


// "CharactorC"
public class CharactorC : Charactor
{
    
// Constructor 
    public CharactorC()
    
{
        
this._symbol = 'C';
        
this._height = 100;
        
this._width = 160;
        
this._ascent = 74;
        
this._descent = 0;
    }


    
//Method
    public override void SetPointSize(int size)
    
{
        
this._pointSize = size;
    }


    
public override void Display()
    
{
        Console.WriteLine(
this._symbol +
          
"pointsize:" + this._pointSize);
    }

}


// "CharactorFactory"
public class CharactorFactory
{
    
// Fields
    private Hashtable charactors = new Hashtable();

    
// Constructor 
    public CharactorFactory()
    
{
        charactors.Add(
"A"new CharactorA());
        charactors.Add(
"B"new CharactorB());
        charactors.Add(
"C"new CharactorC());
    }

       
    
// Method
    public Charactor GetCharactor(string key)
    
{
        Charactor charactor 
= charactors[key] as Charactor;

        
if (charactor == null)
        
{
            
switch (key)
            
{
                
case "A": charactor = new CharactorA(); break;
                
case "B": charactor = new CharactorB(); break
                
case "C": charactor = new CharactorC(); break;
                
//

            }

            charactors.Add(key, charactor);
        }

        
return charactor;
    }

}


public class Program
{
    
public static void Main()
    
{
        CharactorFactory factory 
= new CharactorFactory();

        
// Charactor "A"
        CharactorA ca = (CharactorA)factory.GetCharactor("A");
        ca.SetPointSize(
12);
        ca.Display();
        
        
// Charactor "B"
        CharactorB cb = (CharactorB)factory.GetCharactor("B");
        ca.SetPointSize(
10);
        ca.Display();

        
// Charactor "C"
        CharactorC cc = (CharactorC)factory.GetCharactor("C");
        ca.SetPointSize(
14);
        ca.Display();
    }

}


可以看到這樣的實(shí)現明顯優(yōu)于第一種實(shí)現思路。好了,到這里我們就到到了通過(guò)Flyweight模式實(shí)現了優(yōu)化資源的這樣一個(gè)目的。在這個(gè)過(guò)程中,還有如下幾點(diǎn)需要說(shuō)明:

1.引入CharactorFactory是個(gè)關(guān)鍵,在這里創(chuàng )建對象已經(jīng)不是new一個(gè)Charactor對象那么簡(jiǎn)單,而必須用工廠(chǎng)方法封裝起來(lái)。

2.在這個(gè)例子中把Charactor對象作為Flyweight對象是否準確值的考慮,這里只是為了說(shuō)明Flyweight模式,至于在實(shí)際應用中,哪些對象需要作為Flyweight對象是要經(jīng)過(guò)很好的計算得知,而絕不是憑空臆想。

3.區分內外部狀態(tài)很重要,這是享元對象能做到享元的關(guān)鍵所在。

到這里,其實(shí)我們的討論還沒(méi)有結束。有人可能會(huì )提出如下問(wèn)題,享元對象(Charactor)在這個(gè)系統中相對于每一個(gè)內部狀態(tài)而言它是唯一的,這跟單件模式有什么區別呢?這個(gè)問(wèn)題已經(jīng)很好回答了,那就是單件類(lèi)是不能直接被實(shí)例化的,而享元類(lèi)是可以被實(shí)例化的。事實(shí)上在這里面真正被設計為單件的應該是享元工廠(chǎng)(不是享元)類(lèi),因為如果創(chuàng )建很多個(gè)享元工廠(chǎng)的實(shí)例,那我們所做的一切努力都是白費的,并沒(méi)有減少對象的個(gè)數。修改后的類(lèi)結構圖如下:

9

示意性實(shí)現代碼:

// "CharactorFactory"
public class CharactorFactory
{
    
// Fields
    private Hashtable charactors = new Hashtable();

    
private CharactorFactory instance;
    
// Constructor 
    private CharactorFactory()
    
{
        charactors.Add(
"A"new CharactorA());
        charactors.Add(
"B"new CharactorB());
        charactors.Add(
"C"new CharactorC());
    }

    
    
// Property
    public CharactorFactory Instance
    
{
        
get 
        
{
            
if (instance != null)
            
{
                instance 
= new CharactorFactory();
            }

            
return instance;
        }

    }


    
// Method
    public Charactor GetCharactor(string key)
    
{
        Charactor charactor 
= charactors[key] as Charactor;

        
if (charactor == null)
        
{
            
switch (key)
            
{
                
case "A": charactor = new CharactorA(); break;
                
case "B": charactor = new CharactorB(); break
                
case "C": charactor = new CharactorC(); break;
                
//

            }

            charactors.Add(key, charactor);
        }

        
return charactor;
    }

}


.NET框架中的Flyweight

Flyweight更多時(shí)候的時(shí)候一種底層的設計模式,在我們的實(shí)際應用程序中使用的并不是很多。在.NET中的String類(lèi)型其實(shí)就是運用了Flyweight模式??梢韵胂?,如果每次執行string s1 = “abcd”操作,都創(chuàng )建一個(gè)新的字符串對象的話(huà),內存的開(kāi)銷(xiāo)會(huì )很大。所以.NET中如果第一次創(chuàng )建了這樣的一個(gè)字符串對象s1,下次再創(chuàng )建相同的字符串s2時(shí)只是把它的引用指向“abcd”,這樣就實(shí)現了“abcd”在內存中的共享??梢酝ㄟ^(guò)下面一個(gè)簡(jiǎn)單的程序來(lái)演示s1s2的引用是否一致:

public class Program
{
    
public static void Main(string[] args)
    
{
        
string s1 = "abcd";
        
string s2 = "abcd";

        Console.WriteLine(Object.ReferenceEquals(s1,s2));

        Console.ReadLine();
    }

}


可以看到,輸出的結果為True。但是大家要注意的是如果再有一個(gè)字符串s3,它的初始值為“ab”,再對它進(jìn)行操作s3 = s3 + “cd”,這時(shí)雖然s1s3的值相同,但是它們的引用是不同的。關(guān)于String的詳細情況大家可以參考SDK,這里不再討論了。

效果及實(shí)現要點(diǎn)

1.面向對象很好的解決了抽象性的問(wèn)題,但是作為一個(gè)運行在機器中的程序實(shí)體,我們需要考慮對象的代價(jià)問(wèn)題。Flyweight設計模式主要解決面向對象的代價(jià)問(wèn)題,一般不觸及面向對象的抽象性問(wèn)題。

2Flyweight采用對象共享的做法來(lái)降低系統中對象的個(gè)數,從而降低細粒度對象給系統帶來(lái)的內存壓力。在具體實(shí)現方面,要注意對象狀態(tài)的處理。

3享元模式的優(yōu)點(diǎn)在于它大幅度地降低內存中對象的數量。但是,它做到這一點(diǎn)所付出的代價(jià)也是很高的:享元模式使得系統更加復雜。為了使對象可以共享,需要將一些狀態(tài)外部化,這使得程序的邏輯復雜化。另外它將享元對象的狀態(tài)外部化,而讀取外部狀態(tài)使得運行時(shí)間稍微變長(cháng)。

適用性

當以下所有的條件都滿(mǎn)足時(shí),可以考慮使用享元模式:

1、   一個(gè)系統有大量的對象。

2、   這些對象耗費大量的內存。

3、   這些對象的狀態(tài)中的大部分都可以外部化。

4、   這些對象可以按照內蘊狀態(tài)分成很多的組,當把外蘊對象從對象中剔除時(shí),每一個(gè)組都可以?xún)H用一個(gè)對象代替。

5、   軟件系統不依賴(lài)于這些對象的身份,換言之,這些對象可以是不可分辨的。

滿(mǎn)足以上的這些條件的系統可以使用享元對象。最后,使用享元模式需要維護一個(gè)記錄了系統已有的所有享元的表,而這需要耗費資源。因此,應當在有足夠多的享元實(shí)例可供共享時(shí)才值得使用享元模式。

總結

Flyweight模式解決的是由于大量的細粒度對象所造成的內存開(kāi)銷(xiāo)的問(wèn)題,它在實(shí)際的開(kāi)發(fā)中并不常用,但是作為底層的提升性能的一種手段卻很有效。

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
享元模式詳解
C#面向對象設計模式縱橫談:Flyweight 享元模式
小地圖范例
設計模式學(xué)習筆記(十二)——Flyweight享元模式
享元模式(Flyweight Pattern)
享元模式(Flyweight)解析例子
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久