相對于其它模式,Flyweight模式在PHP實現似乎沒有太大的意義,因為PHP的生命周期就在一個請求,請求執行完了,php占用的資源都被釋放。我們只是為了學習而簡單做了介紹。
1. 概述
面向對象技術可以很好地解決系統一些靈活性或可擴展性或抽象性的問題,但在很多情況下需要在系統中增加類和對象的個數。當對象數量太多時,將導致運行代價過高,帶來性能下降等問題。比如:
例子1:圖形應用中的圖元等對象、字處理應用中的字符對象等。
2.解決方案:
享元模式(Flyweight):對象結構型模式運用共享技術有效地支持大量細粒度的對象。
它使用共享物件,用來盡可能減少內存使用量以及分享資訊給盡可能多的相似物件;它適合用于當大量物件只是重復因而導致無法令人接受的使用大量內存。通常物件中的部分狀態是可以分享。常見做法是把它們放在外部數據結構,當需要使用時再將它們傳遞給享元。
4. 適用性
1)一個應用程序使用大量相同或者相似的對象,造成很大的存儲開銷。
2)對象的大部分狀態都可以外部化,可以將這些外部狀態傳入對象中。
3)如果刪除對象的外部狀態,那么可以用相對較少的共享對象取代很多組對象。
4) 應用程序不依賴于對象標識。由于Flyweight對象可以被共享,對于概念上明顯有別的對象,標識測試將返回真值。
5)使用享元模式需要維護一個存儲享元對象的享元池,而這需要耗費資源,因此,應當在多次重復使用享元對象時才值得使用享元模式
5.結構
6.構建模式的組成
1) 抽象享元類(Flyweight):描述一個接口,通過這個接口flyweight可以接受并作用于外部狀態。
2) 具體享元類(ConcreteFlyweight):實現Flyweight接口 ,并為內部狀態( 如果有的話 )增加存儲空間
。ConcreteFlyweight對象必須是可共享的。它所存儲的狀態必須是內部的;即,它必須獨立于ConcreteFlyweight對象的場景。
3) 非共享具體享元類(UnsharedConcreteFlyweight):— 并非所有的Flyweight子類都需要被共享。Flyweight接口使共享成為可能,但它并不強制共享。在Flyweight對象結構的某些層次,UnsharedConcreteFlyweight對象通常將ConcreteFlyweight對象作為子節點。
4) 享元工廠類(FlyweightFactory):創建并管理flyweight對象, 確保合理地共享flyweight。本角色必須保證享元對象可以被系統適當地共享。當一個客戶端對象調用一個享元對象
flyweight的時候,享元工廠角色(Flyweight Factory對象)會檢查系統中是否已經有一個符合要求的享元對象。如果已經有了,享元工廠角色就應當提供這個已有的享元對象;如果系統中沒有一個適當的享元對象的話,享元工廠角色就應當創建一個合適的享元對象。
5)客戶(Client):維持一個對flyweight的引用。計算或存儲一個(多個)flyweight的外部狀態。
7.
效果
享元模式的優點:
1)享元模式的優點在于它可以極大減少內存中對象的數量,使得相同對象或相似對象在內存中只保存一份。
2)享元模式的外部狀態相對獨立,而且不會影響其內部狀態,從而使得享元對象可以在不同的環境中被共享。
享元模式的缺點:
1)享元模式使得系統更加復雜,需要分離出內部狀態和外部狀態,這使得程序的邏輯復雜化。
2)為了使對象可以共享,享元模式需要將享元對象的狀態外部化,而讀取外部狀態使得運行時間變長。
8.實現
享元模式可以分成單純享元模式和復合享元模式兩種形式。
【單純享元模式】
在單純的享元模式中,所有的享元對象都是可以共享的。
源代碼:
<?php /** * 單純享元模式 * @author guisu */ /** * 抽象享元角色 */ abstract class Flyweight { /** * 示意性方法 * @param string $state 外部狀態 */ abstract public function operation($state); } /** * 具體享元角色 */ class ConcreteFlyweight extends Flyweight { private $_intrinsicState = null; /** * 構造方法 * @param string $state 內部狀態 */ public function __construct($state) { $this->_intrinsicState = $state; } public function operation($state) { echo 'ConcreteFlyweight operation, Intrinsic State = ' . $this->_intrinsicState . ' Extrinsic State = ' . $state . '<br />'; } } /** * 享元工廠角色 */ class FlyweightFactory { private $_flyweights; public function __construct() { $this->_flyweights = array(); } public function getFlyweigth($state) { if (isset($this->_flyweights[$state])) { return $this->_flyweights[$state]; } else { return $this->_flyweights[$state] = new ConcreteFlyweight($state); } } } class Client{ static function main (){ $flyweightFactory = new FlyweightFactory(); $flyweight = $flyweightFactory->getFlyweigth('state A'); $flyweight->operation('other state A'); $flyweight = $flyweightFactory->getFlyweigth('state B'); $flyweight->operation('other state B'); } } ?>【復合享元模式】
復合享元模式對象是由一些單純享元使用合成模式加以復合而成
復合享元角色所代表的對象是不可以共享的,但是一個復合享元對象可以分解成為多個本身是單純享元對象的組合。
<?php /** * 復合享元模式 * */ /** * 抽象享元角色 */ abstract class Flyweight { /** * 示意性方法 * @param string $state 外部狀態 */ abstract public function operation($state); } /** * 具體享元角色 */ class ConcreteFlyweight extends Flyweight { private $_intrinsicState = null; /** * 構造方法 * @param string $state 內部狀態 */ public function __construct($state) { $this->_intrinsicState = $state; } public function operation($state) { echo 'ConcreteFlyweight operation, Intrinsic State = ' . $this->_intrinsicState . ' Extrinsic State = ' . $state . '<br />'; } } /** * 不共享的具體享元,客戶端直接調用 */ class UnsharedConcreteFlyweight extends Flyweight { private $_flyweights; /** * 構造方法 * @param string $state 內部狀態 */ public function __construct() { $this->_flyweights = array(); } public function operation($state) { foreach ($this->_flyweights as $flyweight) { $flyweight->operation($state); } } public function add($state, Flyweight $flyweight) { $this->_flyweights[$state] = $flyweight; } } /** * 享元工廠角色 */ class FlyweightFactory { private $_flyweights; public function __construct() { $this->_flyweights = array(); } public function getFlyweigth($state) { if (is_array($state)) { // 復合模式 $uFlyweight = new UnsharedConcreteFlyweight(); foreach ($state as $row) { $uFlyweight->add($row, $this->getFlyweigth($row)); } return $uFlyweight; } else if (is_string($state)) { if (isset($this->_flyweights[$state])) { return $this->_flyweights[$state]; } else { return $this->_flyweights[$state] = new ConcreteFlyweight($state); } } else { return null; } } } class Client{ static function main (){ $flyweightFactory = new FlyweightFactory(); $flyweight = $flyweightFactory->getFlyweigth('state A'); $flyweight->operation('other state A'); $flyweight = $flyweightFactory->getFlyweigth('state B'); $flyweight->operation('other state B'); /* 復合對象*/ $uflyweight = $flyweightFactory->getFlyweigth(array('state A', 'state B')); $uflyweight->operation('other state A'); } } ?>
9.與其他相關模式
客戶端要引用享元對象,是通過工廠對象創建或者獲得的,客戶端每次引用一個享元對象,都是可以通過同一個工廠對象來引用所需要的享元對象。因此,可以將享元工廠設計成單例模式,這樣就可以保證客戶端只引用一個工廠實例。因為所有的享元對象都是由一個工廠對象統一管理的,所以在客戶端沒有必要引用多個工廠對象。不管是單純享元模式還是復合享元模式中的享元工廠角色,都可以設計成為單例模式,對于結果是不會有任何影響的。
Composite模式:Flyweight模式通常和Composite 模式結合起來,用共享葉結點的有向無環圖實現一個邏輯上的層次結構。復合享元模式實際上是單純享元模式與合成模式的組合。單純享元對象可以作為樹葉對象來講,是可以共享的,而復合享元對象可以作為樹枝對象, 因此在復合享元角色中可以添加聚集管理方法。通常,最好用Flyweight實現State
和Strategy 對象。
10.總結
1) 享元模式是一個考慮系統性能的設計模式,通過使用享元模式可以節約內存空間,提高系統的性能。
2) 享元模式的核心在于享元工廠類,享元工廠類的作用在于提供一個用于存儲享元對象的享元池,用戶需要對象時,首先從享元池中獲取,如果享 元池中不存在,則創 建一個新的享元對象返回給用戶,并在享元池中保存該新增對象。
3) 享元模式以共享的方式高效地支持大量的細粒度對象,享元對象能做到共享的關鍵是區分內部狀態(Internal State)和外部狀態(External State)。
(1) 內部狀態是存儲在享元對象內部并且不會隨環境改變而改變的狀態,因此內部狀態可以共享。
(2) 外部狀態是隨環境改變而改變的、不可以共享的狀態。享元對象的外部狀態必須由客戶端保存,并在享元對象被創建之后,在需要使用的時候 再傳入到享元對 象內部。一個外部狀態與另一個外部狀態之間是相互獨立的。
轉自:http://blog.csdn.net/hguisu/article/details/7535792
原創文章,作者:s19930811,如若轉載,請注明出處:http://www.www58058.com/2924