運用享元技術有效的支援大量細粒度的對象,需要的朋友可以參考下。
享元模式英文稱為“Flyweight Pattern”,我非常感謝將Flyweight Pattern翻譯成享元模式的那位強人,因為這個詞將這個模式使用的方式明白得表示了出來;如果翻譯成為羽量級模式或蠅量級模式等等,雖然可以含蓄的表現出使用此模式達到的目的,但是還是沒有抓住此模式的關鍵。
享元模式的定義為:採用一個共享來避免大量擁有相同內容物件的開銷。這種開銷中最常見、直覺的就是記憶體的損耗。享元模式以共享的方式高效的支援大量的細粒度物件。
享元模式的優點:
1)享元模式的優點在於它可以大幅減少記憶體中物件的數量,使得相同物件或相似物件在記憶體中只保存一份。
2)享元模式的外在狀態相對獨立,而且不會影響其內部狀態,使得享元物件可以在不同的環境中被共享。
享元模式的缺點:
1)享元模式使得系統更加複雜,需要分離內部狀態和外部狀態,這使得程式的邏輯複雜化。
2)為了讓物件可以共享,享元模式需要將享元物件的狀態外部化,而讀取外部狀態使得運行時間變長。
在名字和定義中都體現出了共享這一個核心概念,那麼怎麼來實現共享呢?要知道每個事物都是不同的,但是又有一定的共性,如果只有完全相同的事物才能共享,那麼享元模式可以說就是不可行的;因此我們應該盡量將事物的共性共享,而又保留它的個性。為了做到這一點,享元模式中區分了內蘊狀態和外蘊狀態。內蘊狀態就是共性,外蘊狀態就是個性了。
註:共享的物件必須是不可變的,不然一變則全變(如果有這種需求除外)。
內蘊狀態儲存在享元內部,不會隨環境的改變而有所不同,是可以共享的;外蘊狀態是不可以共享的,它隨環境的改變而改變的,因此外蘊狀態是由客戶端來維持(因為環境的變化是由客戶端引起的)。在每個具體的環境下,客戶端將外蘊狀態傳遞給享元,從而創造出不同的物件出來。
先看看下面程序,大概了解下享元模式。
<?php /** * 享元模式 * * 运用享元技术有效的支持大量细粒度的对象 */ class CD { private $_title = null; private $_artist = null; public function setTitle($title) { $this->_title = $title; } public function getTitle() { return $this->_title; } public function setArtist($artist) { $this->_artist = $artist; } public function getArtist($artist) { return $this->_artist; } } class Artist { private $_name; public function construct($name) { echo "construct ".$name."<br/>"; $this->_name = $name; } public function getName() { return $this->_name; } } class ArtistFactory { private $_artists = array(); public function getArtist($name) { if(isset($this->_artists[$name])) { return $this->_artists[$name]; } else { $objArtist = new Artist($name); $this->_artists[$name] = $objArtist; return $objArtist; } } } $objArtistFactory = new ArtistFactory(); $objCD1 = new CD(); $objCD1->setTitle("title1"); $objCD1->setArtist($objArtistFactory->getArtist('artist1')); $objCD2 = new CD(); $objCD2->setTitle("title2"); $objCD2->setArtist($objArtistFactory->getArtist('artist2')); $objCD3 = new CD(); $objCD3->setTitle("title3"); $objCD3->setArtist($objArtistFactory->getArtist('artist1'));
享元模式的精要有三點:
被系統大量使用的細粒度對象,粒度有多細,量要有多大,看看jdk中使用的享元模式就知道了,jdk中,Integer,Character,String等都使用了享元模式,他們都是最基礎的資料類型 ,不可謂不細,他們頻繁的參與運算,不可謂不大量。
劃分物件的內蘊屬性/狀態與外蘊屬性/狀態;所謂內蘊狀態,就是存在物件的內部,不會隨著環境變化的狀態, 有一個網友說的很好,就是無區別的狀態, 即拿掉外蘊屬性之後同一類對象沒有區別對象的內蘊狀態就是對象的元神,只要元神元神無區別,那麼對像也就無區別,同時也只有這些無差別的元神可以被分享,我想這也是Flyweight被翻譯成享元的原因。外蘊狀態就是由客戶端指定,會隨著環境變化的狀態; 對Integer來說, 他的內蘊屬性其實就是他的value(當然它也沒有外蘊屬性);
用一個工廠控制享元的創造;因為享元物件不能被客戶端隨意創造, 否則就沒有意義了。工廠通常提供快取機制保存已經創造的享元。
物件導向雖然很好地解決了抽象性的問題,但是對於一個實際運作的軟體系統,我們還需要考慮物件導向的代價問題,享元模式解決的就是物件導向的代價問題。享元模式採用物件共享的做法來降低系統中物件的數量,從而降低細粒度物件對系統造成的記憶體壓力。
享元模式在一般的專案開發中並不常用,而是常應用於系統底層的開發,以便解決系統的效能問題。 Java和.Net中的String類型就是使用了享元模式。如果在Java或.NET中已經創建了一個字串物件s1,那麼下次再創建相同的字串s2的時候,系統只是把s2的引用指向s1所引用的具體對象,這實現了相同字串在記憶體中的共享。如果每次執行s1=「abc」操作的時候,都建立一個新的字串物件的話,那麼記憶體的開銷會很大。
以上是php設計模式之FlyWeight (享元模式)的詳細內容。更多資訊請關注PHP中文網其他相關文章!