- 論壇徽章:
- 0
|
本帖最后由 bs 于 2011-03-06 23:42 編輯
以往在php環(huán)境下談到的設(shè)計模式往往都是理論一大堆,加之php較少在實現(xiàn)大型應(yīng)用方面,所以很多時候設(shè)計模式成了一種擺設(shè),本文從較簡單的設(shè)計模型中的單件模式說起,談?wù)剳?yīng)用,闡述設(shè)計模型對于復(fù)雜環(huán)境中的大內(nèi)涵.
從一個簡單的例子著手,在一些應(yīng)用中,我們希望有些對象是全局作用的,如下:
- include('example.class.php');
- $obj = new example();
- class a1
- {
- function ex()
- {
- global $obj;
- $obj->v = 1; //注意這里,需要調(diào)用外部對象
- }
- }
- class a2
- {
- function ex()
- {
- global $obj;
- $obj->v ++; //注意這里,再次調(diào)用外部對象
- }
- }
- $a1 = new a1;
- $a1->ex();
- $a2 = new a2;
- $a2->ex();
復(fù)制代碼 從上面簡單的例子看到,$obj對象被其它多個對象所使用,這時通常需要的幾個步驟:
1. include類文件
2. 實例化
3. 在使用時global聲明全局性
倘若有種情況需要在不同的對象中調(diào)用多個外部對象,那么情況有可能就是如下:
- include('example.class.php');
- $obj = new example();
- include('example2.class.php');
- $obj2 = new example2();
- ...
- $obj3
- $obj4
- $obj_n
- ...
- class a1
- {
- function ex()
- {
- global $obj;
- $obj->v = 1;
- global $obj2;
- $obj2->v = 1;
- ...
- global $obj_n;
- $obj_n->v = 1;
- }
- }
- class a2
- {
- ...
復(fù)制代碼 局面開始不好收拾了,于是我們使用一種方法封裝這個過程,首先定義一個類,這個類專門負(fù)責(zé)將另一個指定的類自動實例化成對象:
- class Singleton
- {
- private $objs;
- public function instance($obj)
- {
- if($this->objs[$obj] == null) //判斷是否已經(jīng)實例化
- {
- include($obj.'.class.php');
- $this->objs[$obj] = new $obj;
- }
- return $this->objs[$obj];
- }
- }
- $Singleton = new Singleton();
復(fù)制代碼 那么之前的局面就演變成如下:
- ...
- class a1
- {
- function ex()
- {
- global $Singleton; //只需一次global聲明
- $Singleton->reg('example')->v = 1;
- $Singleton->reg('example2')->v = 1;
- ...
- $Singleton->reg('example_n')->v = 1;
- ...
- }
- }
- class a2
- {
- ...
復(fù)制代碼 那么其中通過$Singleton對象訪問類就是經(jīng)典的單件模式了,這邊僅僅是說明了單件模式概念,以下說明使用單件模式的好處.
一.文件包含與對象實例化的透明化
我們發(fā)現(xiàn)上邊在使用$Singleton仍然需要global聲明,這時可以使用函數(shù)來"包裝"
- function instance($class_name)
- {
- static $instance;
- if($instance == false)
- $instance = new Singleton();
- return $instance->reg($class_name); //調(diào)用Singleton對象,實例化類并返回對象
- }
復(fù)制代碼 那么最終的調(diào)用就是這樣的
- ...
- class a1
- {
- function ex()
- {
- //這里我們無需使用global,直接使用example類生成的對象
- instance('example')->v = 1;
- instance('example2')->v = 1;
- ...
- }
- }
- class a2
- {
- ...
復(fù)制代碼 這時我們看到使用一個外部對象就變得簡單而清晰了,我們無需關(guān)注example類所在文件的包含和實例化就能直接使用,
這就是使用單件模式對對象透明化的作用.
二.全局(作用域)應(yīng)用
通過之前的代碼得知,我們可以在任何時候使用Singleton得到我們希望使用的對象:
- class a1
- {
- function ex()
- {
- instance('example')->v = 1; //使用單件模式針對example類生成對象并進行操作
- ...
- }
- }
- ...
- class a2
- {
- function ex()
- {
- instance('example')->v ++; //在不同作用域?qū)ν粋對象進行操作
- ...
- }
- }
復(fù)制代碼 在a1和a2的類中調(diào)用example實現(xiàn)的對象時,無需考慮作用域及global聲明,實現(xiàn)跨全局對象的應(yīng)用.
三.事務(wù)性/一致性的應(yīng)用
在一些多線程的語言中,有時希望在同一時間只能有一個線程對對象進行操作,這是線程安全問題,而在php中,類似的情況是資源競爭的解決,如對共享數(shù)據(jù)的讀寫,而使用單件模式則很容易做到,在原有單件模式的基礎(chǔ)上,增加了事務(wù)性
- class Singleton_safe
- {
- private $objs;
- private $mutex;
- public function reg($obj)
- {
- if($objs[$obj] == null) //判斷是否已經(jīng)實例化
- {
- include($obj.'.class.php');
- $this->mutex[$obj] = sem_get(fileinode($obj.'.class.php'),1,0666,true);
- sem_acquire($this->mutex[$obj]); //這邊使用信號量做同步
- $this->objs[$obj] = new $obj;
- }
- return $this->objs[$obj];
- }
- function __destruct()
- {
- foreach($this->mutex as $sem_id)
- {
- sem_release($sem_id); //單件模式下析構(gòu)時刪除所有對象的信號量鎖
- //sem_remove($sem_id);
- }
- }
- }
復(fù)制代碼 當(dāng)然,和其它語言不一樣,這個簡單的例子實現(xiàn)的事務(wù)周期是對象在整個php進程的運行期間,這樣保證了在調(diào)用Singleton_safe實現(xiàn)單例模式下,派生對象的所有操作是系統(tǒng)唯一的.
*四.其它擴展
有時在使用或調(diào)試對象時,需要記錄對象的調(diào)用次數(shù),可增加一些記數(shù)功能,
- class Singleton
- {
- private $objs;
- private $record = 0;
- public function reg($obj)
- {
- if($this->objs[$obj] == null) //判斷是否已經(jīng)實例化
- {
- include($obj.'.class.php');
- $this->objs[$obj] = new $obj;
- }
- $this->record[$obj]++; //累計對象的使用次數(shù)
- return $this->objs[$obj];
- }
- public get_record($obj_name)
- {
- return $this->record[$obj_name]; //獲取對象的使用次數(shù)
- }
- }
- ....
- function instance($class_name == null)
- {
- static $instance;
- if($instance == false)
- $instance = new Singleton();
- if($class_name == null) return $instance;
- return $instance->reg($class_name);
- }
復(fù)制代碼 使用時
- instance('example')->v = 1;
- instance('example')->v++;
- echo 'example被使用次數(shù)為:',instance()->get_record('example');//2
復(fù)制代碼 此外在一些其它語言上,如Cpp上也可結(jié)合對象的創(chuàng)建與銷毀等內(nèi)存管理工作.
單件模式是設(shè)計模式中較簡單同時也是使用最為頻繁的模式之一,僅僅這樣一個簡單的實現(xiàn)便可以幫我們做很多事,也讓我們更多更有必要地去了解設(shè)計模式的價值所在.
另外在代碼中存在Multiton模式的爭議
更純粹的Singleton如下
- //同上
- function instance($class_name)
- {
- static $instance;
- if($instance[$class_name] == false)
- $instance[$class_name] = new Singleton($class_name);
- return $instance[$class_name]
- }
- ...
- class Singleton
- {
- function __construct($class_name)
- {
- include($class_name.'.class.php');
- return new $class_name;
- }
- ...
- }
復(fù)制代碼 調(diào)用上完全相同,算是重新做了Singleton和Multiton區(qū)別 |
|