PHP中單例模式的思考
單例模式的要點(diǎn)有三個(gè):
- 一是某個(gè)類(lèi)只能有一個(gè)實(shí)例;
- 二是它必須自行創(chuàng)建這個(gè)實(shí)例;
- 三是它必須自行向整個(gè)系統(tǒng)提供這個(gè)實(shí)例。
/**
* 設(shè)計(jì)模式之單例模式
* $_instance必須聲明為靜態(tài)的私有變量
* 構(gòu)造函數(shù)必須聲明為私有,防止外部程序new類(lèi)從而失去單例模式的意義
* getInstance()方法必須設(shè)置為公有的,必須調(diào)用此方法以返回實(shí)例的一個(gè)引用
* ::操作符只能訪(fǎng)問(wèn)靜態(tài)變量和靜態(tài)函數(shù)
* new對(duì)象都會(huì)消耗內(nèi)存
* 使用場(chǎng)景:最常用的地方是數(shù)據(jù)庫(kù)連接。
* 使用單例模式生成一個(gè)對(duì)象后,該對(duì)象可以被其它眾多對(duì)象所使用。
*/
class man
{
//保存例實(shí)例在此屬性中
private static $_instance;
//構(gòu)造函數(shù)聲明為private,防止直接創(chuàng)建對(duì)象
private function __construct()
{
echo '我被實(shí)例化了!';
}
//單例方法
public static function get_instance()
{
var_dump(isset(self::$_instance));
if(!isset(self::$_instance))
{
self::$_instance=new self();
}
return self::$_instance;
}
//阻止用戶(hù)復(fù)制對(duì)象實(shí)例
private function __clone()
{
trigger_error('Clone is not allow' ,E_USER_ERROR);
}
function test()
{
echo("test");
}
}
// 這個(gè)寫(xiě)法會(huì)出錯(cuò),因?yàn)闃?gòu)造方法被聲明為private
//$test = new man;
// 下面將得到Example類(lèi)的單例對(duì)象
$test = man::get_instance();
$test = man::get_instance();
$test->test();
// 復(fù)制對(duì)象將導(dǎo)致一個(gè)E_USER_ERROR.
//$test_clone = clone $test;
以上是我在網(wǎng)絡(luò)上看到的PHP單例模式的基本代碼。單例模式的主要作用是節(jié)省資源,禁止類(lèi)被反復(fù)new。但是在PHP語(yǔ)言當(dāng)中,根本不會(huì)存在這一情況。PHP腳本在每次運(yùn)行完成后,會(huì)自動(dòng)回收釋放的資源。如果你真的只需要實(shí)例化某個(gè)類(lèi)一次,那么只要在之后的代碼中不再將其實(shí)例化就好。完全不需要在代碼層面上作出限制。與此同時(shí),單例模式會(huì)讓單元測(cè)試和代碼維護(hù)的成本增高。
但這也并不意味著,單例模式百無(wú)一用。下面這段引用是我從Stackoverflow中看到的一段答案,讀完了之后發(fā)現(xiàn)很有趣也很諷刺。
you will find that very often something that you are absolutely sure that you'll never have more than one instance of, you eventually have a second ... When this happens, if you have used a static class you're in for a much worse refactor than if you had used a singleton ... it converts fairly easily to an intelligent factory pattern--can even be converted to use dependency injection without too much trouble. For instance, if your singleton is gotten through getInstance(), you can pretty easily change that to getInstance(databaseName) and allow for multiple databases--no other code changes.
不知道你是不是也很無(wú)語(yǔ),單例模式最大的用出竟是是在當(dāng)你需要一個(gè)以上的實(shí)例時(shí)讓代碼的修改更簡(jiǎn)單化……